3 * \brief event handling
4 * \see mlt_events_struct
6 * Copyright (C) 2004-2009 Ushodaya Enterprises Limited
7 * \author Charles Yates <charles.yates@pandora.be>
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library 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 GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 #include "mlt_properties.h"
30 #include "mlt_events.h"
32 /* Memory leak checks. */
34 #undef _MLT_EVENT_CHECKS_
36 #ifdef _MLT_EVENT_CHECKS_
37 static int events_created = 0;
38 static int events_destroyed = 0;
41 /** \brief Events class
43 * Events provide messages and notifications between services and the application.
44 * A service can register an event and fire/send it upon certain conditions or times.
45 * Likewise, a service or an application can listen/receive specific events on specific
49 struct mlt_events_struct
55 typedef struct mlt_events_struct *mlt_events;
57 /** \brief Event class
61 struct mlt_event_struct
66 mlt_listener listener;
70 /** Increment the reference count on self event.
72 * \public \memberof mlt_event_struct
73 * \param self an event
76 void mlt_event_inc_ref( mlt_event self )
82 /** Increment the block count on self event.
84 * \public \memberof mlt_event_struct
85 * \param self an event
88 void mlt_event_block( mlt_event self )
90 if ( self != NULL && self->owner != NULL )
94 /** Decrement the block count on self event.
96 * \public \memberof mlt_event_struct
97 * \param self an event
100 void mlt_event_unblock( mlt_event self )
102 if ( self != NULL && self->owner != NULL )
103 self->block_count --;
106 /** Close self event.
108 * \public \memberof mlt_event_struct
109 * \param self an event
112 void mlt_event_close( mlt_event self )
116 if ( -- self->ref_count == 1 )
118 if ( self->ref_count <= 0 )
120 #ifdef _MLT_EVENT_CHECKS_
121 mlt_log( NULL, MLT_LOG_DEBUG, "Events created %d, destroyed %d\n", events_created, ++events_destroyed );
128 /* Forward declaration to private functions.
131 static mlt_events mlt_events_fetch( mlt_properties );
132 static void mlt_events_store( mlt_properties, mlt_events );
133 static void mlt_events_close( mlt_events );
135 /** Initialise the events structure.
137 * \public \memberof mlt_events_struct
138 * \param self a properties list
141 void mlt_events_init( mlt_properties self )
143 mlt_events events = mlt_events_fetch( self );
144 if ( events == NULL )
146 events = calloc( 1, sizeof( struct mlt_events_struct ) );
147 events->list = mlt_properties_new( );
148 mlt_events_store( self, events );
152 /** Register an event and transmitter.
154 * \public \memberof mlt_events_struct
155 * \param self a properties list
156 * \param id the name of an event
157 * \param transmitter the callback function to send an event message
158 * \return true if there was an error
161 int mlt_events_register( mlt_properties self, const char *id, mlt_transmitter transmitter )
164 mlt_events events = mlt_events_fetch( self );
165 if ( events != NULL )
167 mlt_properties list = events->list;
169 error = mlt_properties_set_data( list, id, transmitter, 0, NULL, NULL );
170 sprintf( temp, "list:%s", id );
171 if ( mlt_properties_get_data( list, temp, NULL ) == NULL )
172 mlt_properties_set_data( list, temp, mlt_properties_new( ), 0, ( mlt_destructor )mlt_properties_close, NULL );
179 * This takes a variable number of arguments to supply to the listener.
181 * \public \memberof mlt_events_struct
182 * \param self a properties list
183 * \param id the name of an event
184 * \return the number of listeners
187 int mlt_events_fire( mlt_properties self, const char *id, ... )
190 mlt_events events = mlt_events_fetch( self );
191 if ( events != NULL )
196 mlt_properties list = events->list;
197 mlt_properties listeners = NULL;
199 mlt_transmitter transmitter = mlt_properties_get_data( list, id, NULL );
200 sprintf( temp, "list:%s", id );
201 listeners = mlt_properties_get_data( list, temp, NULL );
203 va_start( alist, id );
205 args[ i ] = va_arg( alist, void * );
206 while( args[ i ++ ] != NULL );
209 if ( listeners != NULL )
211 for ( i = 0; i < mlt_properties_count( listeners ); i ++ )
213 mlt_event event = mlt_properties_get_data_at( listeners, i, NULL );
214 if ( event != NULL && event->owner != NULL && event->block_count == 0 )
216 if ( transmitter != NULL )
217 transmitter( event->listener, event->owner, event->service, args );
219 event->listener( event->owner, event->service );
228 /** Register a listener.
230 * \public \memberof mlt_events_struct
231 * \param self a properties list
232 * \param service an opaque pointer
233 * \param id the name of the event to listen for
234 * \param listener the callback to receive an event message
238 mlt_event mlt_events_listen( mlt_properties self, void *service, const char *id, mlt_listener listener )
240 mlt_event event = NULL;
241 mlt_events events = mlt_events_fetch( self );
242 if ( events != NULL )
244 mlt_properties list = events->list;
245 mlt_properties listeners = NULL;
247 sprintf( temp, "list:%s", id );
248 listeners = mlt_properties_get_data( list, temp, NULL );
249 if ( listeners != NULL )
253 for ( i = 0; event == NULL && i < mlt_properties_count( listeners ); i ++ )
255 mlt_event entry = mlt_properties_get_data_at( listeners, i, NULL );
256 if ( entry != NULL && entry->owner != NULL )
258 if ( entry->service == service && entry->listener == listener )
261 else if ( ( entry == NULL || entry->owner == NULL ) && first_null == -1 )
269 event = malloc( sizeof( struct mlt_event_struct ) );
272 #ifdef _MLT_EVENT_CHECKS_
275 sprintf( temp, "%d", first_null == -1 ? mlt_properties_count( listeners ) : first_null );
276 event->owner = events;
277 event->ref_count = 0;
278 event->block_count = 0;
279 event->listener = listener;
280 event->service = service;
281 mlt_properties_set_data( listeners, temp, event, 0, ( mlt_destructor )mlt_event_close, NULL );
282 mlt_event_inc_ref( event );
291 /** Block all events for a given service.
293 * \public \memberof mlt_events_struct
294 * \param self a properties list
295 * \param service an opaque pointer
298 void mlt_events_block( mlt_properties self, void *service )
300 mlt_events events = mlt_events_fetch( self );
301 if ( events != NULL )
304 mlt_properties list = events->list;
305 for ( j = 0; j < mlt_properties_count( list ); j ++ )
307 char *temp = mlt_properties_get_name( list, j );
308 if ( !strncmp( temp, "list:", 5 ) )
310 mlt_properties listeners = mlt_properties_get_data( list, temp, NULL );
311 for ( i = 0; i < mlt_properties_count( listeners ); i ++ )
313 mlt_event entry = mlt_properties_get_data_at( listeners, i, NULL );
314 if ( entry != NULL && entry->service == service )
315 mlt_event_block( entry );
322 /** Unblock all events for a given service.
324 * \public \memberof mlt_events_struct
325 * \param self a properties list
326 * \param service an opaque pointer
329 void mlt_events_unblock( mlt_properties self, void *service )
331 mlt_events events = mlt_events_fetch( self );
332 if ( events != NULL )
335 mlt_properties list = events->list;
336 for ( j = 0; j < mlt_properties_count( list ); j ++ )
338 char *temp = mlt_properties_get_name( list, j );
339 if ( !strncmp( temp, "list:", 5 ) )
341 mlt_properties listeners = mlt_properties_get_data( list, temp, NULL );
342 for ( i = 0; i < mlt_properties_count( listeners ); i ++ )
344 mlt_event entry = mlt_properties_get_data_at( listeners, i, NULL );
345 if ( entry != NULL && entry->service == service )
346 mlt_event_unblock( entry );
353 /** Disconnect all events for a given service.
355 * \public \memberof mlt_events_struct
356 * \param self a properties list
357 * \param service an opaque pointer
360 void mlt_events_disconnect( mlt_properties self, void *service )
362 mlt_events events = mlt_events_fetch( self );
363 if ( events != NULL )
366 mlt_properties list = events->list;
367 for ( j = 0; j < mlt_properties_count( list ); j ++ )
369 char *temp = mlt_properties_get_name( list, j );
370 if ( !strncmp( temp, "list:", 5 ) )
372 mlt_properties listeners = mlt_properties_get_data( list, temp, NULL );
373 for ( i = 0; i < mlt_properties_count( listeners ); i ++ )
375 mlt_event entry = mlt_properties_get_data_at( listeners, i, NULL );
376 char *name = mlt_properties_get_name( listeners, i );
377 if ( entry != NULL && entry->service == service )
378 mlt_properties_set_data( listeners, name, NULL, 0, NULL, NULL );
385 /** \brief private to mlt_events_struct, used by mlt_events_wait_for() */
390 pthread_mutex_t mutex;
394 /** The event listener callback for the wait functions.
396 * \private \memberof mlt_events_struct
397 * \param self a properties list
398 * \param pair a condition pair
401 static void mlt_events_listen_for( mlt_properties self, condition_pair *pair )
403 pthread_mutex_lock( &pair->mutex );
404 pthread_cond_signal( &pair->cond );
405 pthread_mutex_unlock( &pair->mutex );
408 /** Prepare to wait for an event.
410 * \public \memberof mlt_events_struct
411 * \param self a properties list
412 * \param id the name of the event to wait for
416 mlt_event mlt_events_setup_wait_for( mlt_properties self, const char *id )
418 condition_pair *pair = malloc( sizeof( condition_pair ) );
419 pthread_cond_init( &pair->cond, NULL );
420 pthread_mutex_init( &pair->mutex, NULL );
421 pthread_mutex_lock( &pair->mutex );
422 return mlt_events_listen( self, pair, id, ( mlt_listener )mlt_events_listen_for );
425 /** Wait for an event.
427 * \public \memberof mlt_events_struct
428 * \param self a properties list
429 * \param event an event
432 void mlt_events_wait_for( mlt_properties self, mlt_event event )
436 condition_pair *pair = event->service;
437 pthread_cond_wait( &pair->cond, &pair->mutex );
441 /** Cleanup after waiting for an event.
443 * \public \memberof mlt_events_struct
444 * \param self a properties list
445 * \param event an event
448 void mlt_events_close_wait_for( mlt_properties self, mlt_event event )
452 condition_pair *pair = event->service;
454 pthread_mutex_unlock( &pair->mutex );
455 pthread_mutex_destroy( &pair->mutex );
456 pthread_cond_destroy( &pair->cond );
461 /** Fetch the events object.
463 * \private \memberof mlt_events_struct
464 * \param self a properties list
465 * \return an events object
468 static mlt_events mlt_events_fetch( mlt_properties self )
470 mlt_events events = NULL;
472 events = mlt_properties_get_data( self, "_events", NULL );
476 /** Store the events object.
478 * \private \memberof mlt_events_struct
479 * \param self a properties list
480 * \param events an events object
483 static void mlt_events_store( mlt_properties self, mlt_events events )
485 if ( self != NULL && events != NULL )
486 mlt_properties_set_data( self, "_events", events, 0, ( mlt_destructor )mlt_events_close, NULL );
489 /** Close the events object.
491 * \private \memberof mlt_events_struct
492 * \param events an events object
495 static void mlt_events_close( mlt_events events )
497 if ( events != NULL )
499 mlt_properties_close( events->list );