]> git.sesse.net Git - mlt/blob - src/framework/mlt_events.c
src/framework/*: improve the doxygen documentation (work in progress). This also...
[mlt] / src / framework / mlt_events.c
1 /**
2  * \file mlt_events.c
3  * \brief event handling
4  *
5  * Copyright (C) 2004-2008 Ushodaya Enterprises Limited
6  * \author Charles Yates <charles.yates@pandora.be>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22
23 #include <stdlib.h>
24 #include <stdarg.h>
25 #include <string.h>
26 #include <pthread.h>
27
28 #include "mlt_properties.h"
29 #include "mlt_events.h"
30
31 /** Memory leak checks. */
32
33 #undef _MLT_EVENT_CHECKS_
34
35 #ifdef _MLT_EVENT_CHECKS_
36 static int events_created = 0;
37 static int events_destroyed = 0;
38 #endif
39
40 /** \brief Events class
41  *
42  */
43
44 struct mlt_events_struct
45 {
46         mlt_properties owner;
47         mlt_properties list;
48 };
49
50 typedef struct mlt_events_struct *mlt_events;
51
52 /** \brief Event class
53  *
54  */
55
56 struct mlt_event_struct
57 {
58         mlt_events owner;
59         int ref_count;
60         int block_count;
61         mlt_listener listener;
62         void *service;
63 };
64
65 /** Increment the reference count on this event.
66 */
67
68 void mlt_event_inc_ref( mlt_event this )
69 {
70         if ( this != NULL )
71                 this->ref_count ++;
72 }
73
74 /** Increment the block count on this event.
75 */
76
77 void mlt_event_block( mlt_event this )
78 {
79         if ( this != NULL && this->owner != NULL )
80                 this->block_count ++;
81 }
82
83 /** Decrement the block count on this event.
84 */
85
86 void mlt_event_unblock( mlt_event this )
87 {
88         if ( this != NULL && this->owner != NULL )
89                 this->block_count --;
90 }
91
92 /** Close this event.
93 */
94
95 void mlt_event_close( mlt_event this )
96 {
97         if ( this != NULL )
98         {
99                 if ( -- this->ref_count == 1 )
100                         this->owner = NULL;
101                 if ( this->ref_count <= 0 )
102                 {
103 #ifdef _MLT_EVENT_CHECKS_
104                         events_destroyed ++;
105                         fprintf( stderr, "Events created %d, destroyed %d\n", events_created, events_destroyed );
106 #endif
107                         free( this );
108                 }
109         }
110 }
111
112 /* Forward declaration to private functions.
113 */
114
115 static mlt_events mlt_events_fetch( mlt_properties );
116 static void mlt_events_store( mlt_properties, mlt_events );
117 static void mlt_events_close( mlt_events );
118
119 /** Initialise the events structure.
120 */
121
122 void mlt_events_init( mlt_properties this )
123 {
124         mlt_events events = mlt_events_fetch( this );
125         if ( events == NULL )
126         {
127                 events = malloc( sizeof( struct mlt_events_struct ) );
128                 events->list = mlt_properties_new( );
129                 mlt_events_store( this, events );
130         }
131 }
132
133 /** Register an event and transmitter.
134 */
135
136 int mlt_events_register( mlt_properties this, char *id, mlt_transmitter transmitter )
137 {
138         int error = 1;
139         mlt_events events = mlt_events_fetch( this );
140         if ( events != NULL )
141         {
142                 mlt_properties list = events->list;
143                 char temp[ 128 ];
144                 error = mlt_properties_set_data( list, id, transmitter, 0, NULL, NULL );
145                 sprintf( temp, "list:%s", id );
146                 if ( mlt_properties_get_data( list, temp, NULL ) == NULL )
147                         mlt_properties_set_data( list, temp, mlt_properties_new( ), 0, ( mlt_destructor )mlt_properties_close, NULL );
148         }
149         return error;
150 }
151
152 /** Fire an event.
153 */
154
155 void mlt_events_fire( mlt_properties this, char *id, ... )
156 {
157         mlt_events events = mlt_events_fetch( this );
158         if ( events != NULL )
159         {
160                 int i = 0;
161                 va_list alist;
162                 void *args[ 10 ];
163                 mlt_properties list = events->list;
164                 mlt_properties listeners = NULL;
165                 char temp[ 128 ];
166                 mlt_transmitter transmitter = mlt_properties_get_data( list, id, NULL );
167                 sprintf( temp, "list:%s", id );
168                 listeners = mlt_properties_get_data( list, temp, NULL );
169
170                 va_start( alist, id );
171                 do
172                         args[ i ] = va_arg( alist, void * );
173                 while( args[ i ++ ] != NULL );
174                 va_end( alist );
175
176                 if ( listeners != NULL )
177                 {
178                         for ( i = 0; i < mlt_properties_count( listeners ); i ++ )
179                         {
180                                 mlt_event event = mlt_properties_get_data_at( listeners, i, NULL );
181                                 if ( event != NULL && event->owner != NULL && event->block_count == 0 )
182                                 {
183                                         if ( transmitter != NULL )
184                                                 transmitter( event->listener, event->owner, event->service, args );
185                                         else
186                                                 event->listener( event->owner, event->service );
187                                 }
188                         }
189                 }
190         }
191 }
192
193 /** Register a listener.
194 */
195
196 mlt_event mlt_events_listen( mlt_properties this, void *service, char *id, mlt_listener listener )
197 {
198         mlt_event event = NULL;
199         mlt_events events = mlt_events_fetch( this );
200         if ( events != NULL )
201         {
202                 mlt_properties list = events->list;
203                 mlt_properties listeners = NULL;
204                 char temp[ 128 ];
205                 sprintf( temp, "list:%s", id );
206                 listeners = mlt_properties_get_data( list, temp, NULL );
207                 if ( listeners != NULL )
208                 {
209                         int first_null = -1;
210                         int i = 0;
211                         for ( i = 0; event == NULL && i < mlt_properties_count( listeners ); i ++ )
212                         {
213                                 mlt_event entry = mlt_properties_get_data_at( listeners, i, NULL );
214                                 if ( entry != NULL && entry->owner != NULL )
215                                 {
216                                         if ( entry->service == service && entry->listener == listener )
217                                                 event = entry;
218                                 }
219                                 else if ( ( entry == NULL || entry->owner == NULL ) && first_null == -1 )
220                                 {
221                                         first_null = i;
222                                 }
223                         }
224
225                         if ( event == NULL )
226                         {
227                                 event = malloc( sizeof( struct mlt_event_struct ) );
228                                 if ( event != NULL )
229                                 {
230 #ifdef _MLT_EVENT_CHECKS_
231                                         events_created ++;
232 #endif
233                                         sprintf( temp, "%d", first_null == -1 ? mlt_properties_count( listeners ) : first_null );
234                                         event->owner = events;
235                                         event->ref_count = 0;
236                                         event->block_count = 0;
237                                         event->listener = listener;
238                                         event->service = service;
239                                         mlt_properties_set_data( listeners, temp, event, 0, ( mlt_destructor )mlt_event_close, NULL );
240                                         mlt_event_inc_ref( event );
241                                 }
242                         }
243
244                 }
245         }
246         return event;
247 }
248
249 /** Block all events for a given service.
250 */
251
252 void mlt_events_block( mlt_properties this, void *service )
253 {
254         mlt_events events = mlt_events_fetch( this );
255         if ( events != NULL )
256         {
257                 int i = 0, j = 0;
258                 mlt_properties list = events->list;
259                 for ( j = 0; j < mlt_properties_count( list ); j ++ )
260                 {
261                         char *temp = mlt_properties_get_name( list, j );
262                         if ( !strncmp( temp, "list:", 5 ) )
263                         {
264                                 mlt_properties listeners = mlt_properties_get_data( list, temp, NULL );
265                                 for ( i = 0; i < mlt_properties_count( listeners ); i ++ )
266                                 {
267                                         mlt_event entry = mlt_properties_get_data_at( listeners, i, NULL );
268                                         if ( entry != NULL && entry->service == service )
269                                                 mlt_event_block( entry );
270                                 }
271                         }
272                 }
273         }
274 }
275
276 /** Unblock all events for a given service.
277 */
278
279 void mlt_events_unblock( mlt_properties this, void *service )
280 {
281         mlt_events events = mlt_events_fetch( this );
282         if ( events != NULL )
283         {
284                 int i = 0, j = 0;
285                 mlt_properties list = events->list;
286                 for ( j = 0; j < mlt_properties_count( list ); j ++ )
287                 {
288                         char *temp = mlt_properties_get_name( list, j );
289                         if ( !strncmp( temp, "list:", 5 ) )
290                         {
291                                 mlt_properties listeners = mlt_properties_get_data( list, temp, NULL );
292                                 for ( i = 0; i < mlt_properties_count( listeners ); i ++ )
293                                 {
294                                         mlt_event entry = mlt_properties_get_data_at( listeners, i, NULL );
295                                         if ( entry != NULL && entry->service == service )
296                                                 mlt_event_unblock( entry );
297                                 }
298                         }
299                 }
300         }
301 }
302
303 /** Disconnect all events for a given service.
304 */
305
306 void mlt_events_disconnect( mlt_properties this, void *service )
307 {
308         mlt_events events = mlt_events_fetch( this );
309         if ( events != NULL )
310         {
311                 int i = 0, j = 0;
312                 mlt_properties list = events->list;
313                 for ( j = 0; j < mlt_properties_count( list ); j ++ )
314                 {
315                         char *temp = mlt_properties_get_name( list, j );
316                         if ( !strncmp( temp, "list:", 5 ) )
317                         {
318                                 mlt_properties listeners = mlt_properties_get_data( list, temp, NULL );
319                                 for ( i = 0; i < mlt_properties_count( listeners ); i ++ )
320                                 {
321                                         mlt_event entry = mlt_properties_get_data_at( listeners, i, NULL );
322                                         char *name = mlt_properties_get_name( listeners, i );
323                                         if ( entry != NULL && entry->service == service )
324                                                 mlt_properties_set_data( listeners, name, NULL, 0, NULL, NULL );
325                                 }
326                         }
327                 }
328         }
329 }
330
331 /** \brief private to mlt_events_struct, used by mlt_events_wait_for() */
332
333 typedef struct
334 {
335         int done;
336         pthread_cond_t cond;
337         pthread_mutex_t mutex;
338 }
339 condition_pair;
340
341 static void mlt_events_listen_for( mlt_properties this, condition_pair *pair )
342 {
343         pthread_mutex_lock( &pair->mutex );
344         if ( pair->done == 0 )
345         {
346                 pthread_cond_signal( &pair->cond );
347                 pthread_mutex_unlock( &pair->mutex );
348         }
349 }
350
351 mlt_event mlt_events_setup_wait_for( mlt_properties this, char *id )
352 {
353         condition_pair *pair = malloc( sizeof( condition_pair ) );
354         pair->done = 0;
355         pthread_cond_init( &pair->cond, NULL );
356         pthread_mutex_init( &pair->mutex, NULL );
357         pthread_mutex_lock( &pair->mutex );
358         return mlt_events_listen( this, pair, id, ( mlt_listener )mlt_events_listen_for );
359 }
360
361 void mlt_events_wait_for( mlt_properties this, mlt_event event )
362 {
363         if ( event != NULL )
364         {
365                 condition_pair *pair = event->service;
366                 pthread_cond_wait( &pair->cond, &pair->mutex );
367         }
368 }
369
370 void mlt_events_close_wait_for( mlt_properties this, mlt_event event )
371 {
372         if ( event != NULL )
373         {
374                 condition_pair *pair = event->service;
375                 event->owner = NULL;
376                 pair->done = 0;
377                 pthread_mutex_unlock( &pair->mutex );
378                 pthread_mutex_destroy( &pair->mutex );
379                 pthread_cond_destroy( &pair->cond );
380         }
381 }
382
383 /** Fetch the events object.
384 */
385
386 static mlt_events mlt_events_fetch( mlt_properties this )
387 {
388         mlt_events events = NULL;
389         if ( this != NULL )
390                 events = mlt_properties_get_data( this, "_events", NULL );
391         return events;
392 }
393
394 /** Store the events object.
395 */
396
397 static void mlt_events_store( mlt_properties this, mlt_events events )
398 {
399         if ( this != NULL && events != NULL )
400                 mlt_properties_set_data( this, "_events", events, 0, ( mlt_destructor )mlt_events_close, NULL );
401 }
402
403 /** Close the events object.
404 */
405
406 static void mlt_events_close( mlt_events events )
407 {
408         if ( events != NULL )
409         {
410                 mlt_properties_close( events->list );
411                 free( events );
412         }
413 }
414