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 this event.
72 * \public \memberof mlt_event_struct
73 * \param this an event
76 void mlt_event_inc_ref( mlt_event
this )
82 /** Increment the block count on this event.
84 * \public \memberof mlt_event_struct
85 * \param this an event
88 void mlt_event_block( mlt_event
this )
90 if ( this != NULL
&& this->owner
!= NULL
)
94 /** Decrement the block count on this event.
96 * \public \memberof mlt_event_struct
97 * \param this an event
100 void mlt_event_unblock( mlt_event
this )
102 if ( this != NULL
&& this->owner
!= NULL
)
103 this->block_count
--;
106 /** Close this event.
108 * \public \memberof mlt_event_struct
109 * \param this an event
112 void mlt_event_close( mlt_event
this )
116 if ( -- this->ref_count
== 1 )
118 if ( this->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 this a properties list
141 void mlt_events_init( mlt_properties
this )
143 mlt_events events
= mlt_events_fetch( this );
144 if ( events
== NULL
)
146 events
= malloc( sizeof( struct mlt_events_struct
) );
147 events
->list
= mlt_properties_new( );
148 mlt_events_store( this, events
);
152 /** Register an event and transmitter.
154 * \public \memberof mlt_events_struct
155 * \param this 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
this, char *id
, mlt_transmitter transmitter
)
164 mlt_events events
= mlt_events_fetch( this );
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 this a properties list
183 * \param id the name of an event
186 void mlt_events_fire( mlt_properties
this, const char *id
, ... )
188 mlt_events events
= mlt_events_fetch( this );
189 if ( events
!= NULL
)
194 mlt_properties list
= events
->list
;
195 mlt_properties listeners
= NULL
;
197 mlt_transmitter transmitter
= mlt_properties_get_data( list
, id
, NULL
);
198 sprintf( temp
, "list:%s", id
);
199 listeners
= mlt_properties_get_data( list
, temp
, NULL
);
201 va_start( alist
, id
);
203 args
[ i
] = va_arg( alist
, void * );
204 while( args
[ i
++ ] != NULL
);
207 if ( listeners
!= NULL
)
209 for ( i
= 0; i
< mlt_properties_count( listeners
); i
++ )
211 mlt_event event
= mlt_properties_get_data_at( listeners
, i
, NULL
);
212 if ( event
!= NULL
&& event
->owner
!= NULL
&& event
->block_count
== 0 )
214 if ( transmitter
!= NULL
)
215 transmitter( event
->listener
, event
->owner
, event
->service
, args
);
217 event
->listener( event
->owner
, event
->service
);
224 /** Register a listener.
226 * \public \memberof mlt_events_struct
227 * \param this a properties list
228 * \param service an opaque pointer
229 * \param id the name of the event to listen for
230 * \param listener the callback to receive an event message
234 mlt_event
mlt_events_listen( mlt_properties
this, void *service
, const char *id
, mlt_listener listener
)
236 mlt_event event
= NULL
;
237 mlt_events events
= mlt_events_fetch( this );
238 if ( events
!= NULL
)
240 mlt_properties list
= events
->list
;
241 mlt_properties listeners
= NULL
;
243 sprintf( temp
, "list:%s", id
);
244 listeners
= mlt_properties_get_data( list
, temp
, NULL
);
245 if ( listeners
!= NULL
)
249 for ( i
= 0; event
== NULL
&& i
< mlt_properties_count( listeners
); i
++ )
251 mlt_event entry
= mlt_properties_get_data_at( listeners
, i
, NULL
);
252 if ( entry
!= NULL
&& entry
->owner
!= NULL
)
254 if ( entry
->service
== service
&& entry
->listener
== listener
)
257 else if ( ( entry
== NULL
|| entry
->owner
== NULL
) && first_null
== -1 )
265 event
= malloc( sizeof( struct mlt_event_struct
) );
268 #ifdef _MLT_EVENT_CHECKS_
271 sprintf( temp
, "%d", first_null
== -1 ?
mlt_properties_count( listeners
) : first_null
);
272 event
->owner
= events
;
273 event
->ref_count
= 0;
274 event
->block_count
= 0;
275 event
->listener
= listener
;
276 event
->service
= service
;
277 mlt_properties_set_data( listeners
, temp
, event
, 0, ( mlt_destructor
)mlt_event_close
, NULL
);
278 mlt_event_inc_ref( event
);
287 /** Block all events for a given service.
289 * \public \memberof mlt_events_struct
290 * \param this a properties list
291 * \param service an opaque pointer
294 void mlt_events_block( mlt_properties
this, void *service
)
296 mlt_events events
= mlt_events_fetch( this );
297 if ( events
!= NULL
)
300 mlt_properties list
= events
->list
;
301 for ( j
= 0; j
< mlt_properties_count( list
); j
++ )
303 char *temp
= mlt_properties_get_name( list
, j
);
304 if ( !strncmp( temp
, "list:", 5 ) )
306 mlt_properties listeners
= mlt_properties_get_data( list
, temp
, NULL
);
307 for ( i
= 0; i
< mlt_properties_count( listeners
); i
++ )
309 mlt_event entry
= mlt_properties_get_data_at( listeners
, i
, NULL
);
310 if ( entry
!= NULL
&& entry
->service
== service
)
311 mlt_event_block( entry
);
318 /** Unblock all events for a given service.
320 * \public \memberof mlt_events_struct
321 * \param this a properties list
322 * \param service an opaque pointer
325 void mlt_events_unblock( mlt_properties
this, void *service
)
327 mlt_events events
= mlt_events_fetch( this );
328 if ( events
!= NULL
)
331 mlt_properties list
= events
->list
;
332 for ( j
= 0; j
< mlt_properties_count( list
); j
++ )
334 char *temp
= mlt_properties_get_name( list
, j
);
335 if ( !strncmp( temp
, "list:", 5 ) )
337 mlt_properties listeners
= mlt_properties_get_data( list
, temp
, NULL
);
338 for ( i
= 0; i
< mlt_properties_count( listeners
); i
++ )
340 mlt_event entry
= mlt_properties_get_data_at( listeners
, i
, NULL
);
341 if ( entry
!= NULL
&& entry
->service
== service
)
342 mlt_event_unblock( entry
);
349 /** Disconnect all events for a given service.
351 * \public \memberof mlt_events_struct
352 * \param this a properties list
353 * \param service an opaque pointer
356 void mlt_events_disconnect( mlt_properties
this, void *service
)
358 mlt_events events
= mlt_events_fetch( this );
359 if ( events
!= NULL
)
362 mlt_properties list
= events
->list
;
363 for ( j
= 0; j
< mlt_properties_count( list
); j
++ )
365 char *temp
= mlt_properties_get_name( list
, j
);
366 if ( !strncmp( temp
, "list:", 5 ) )
368 mlt_properties listeners
= mlt_properties_get_data( list
, temp
, NULL
);
369 for ( i
= 0; i
< mlt_properties_count( listeners
); i
++ )
371 mlt_event entry
= mlt_properties_get_data_at( listeners
, i
, NULL
);
372 char *name
= mlt_properties_get_name( listeners
, i
);
373 if ( entry
!= NULL
&& entry
->service
== service
)
374 mlt_properties_set_data( listeners
, name
, NULL
, 0, NULL
, NULL
);
381 /** \brief private to mlt_events_struct, used by mlt_events_wait_for() */
387 pthread_mutex_t mutex
;
391 /** The event listener callback for the wait functions.
393 * \private \memberof mlt_events_struct
394 * \param this a properties list
395 * \param pair a condition pair
398 static void mlt_events_listen_for( mlt_properties
this, condition_pair
*pair
)
400 pthread_mutex_lock( &pair
->mutex
);
401 if ( pair
->done
== 0 )
403 pthread_cond_signal( &pair
->cond
);
404 pthread_mutex_unlock( &pair
->mutex
);
408 /** Prepare to wait for an event.
410 * \public \memberof mlt_events_struct
411 * \param this a properties list
412 * \param id the name of the event to wait for
416 mlt_event
mlt_events_setup_wait_for( mlt_properties
this, const char *id
)
418 condition_pair
*pair
= malloc( sizeof( condition_pair
) );
420 pthread_cond_init( &pair
->cond
, NULL
);
421 pthread_mutex_init( &pair
->mutex
, NULL
);
422 pthread_mutex_lock( &pair
->mutex
);
423 return mlt_events_listen( this, pair
, id
, ( mlt_listener
)mlt_events_listen_for
);
426 /** Wait for an event.
428 * \public \memberof mlt_events_struct
429 * \param this a properties list
430 * \param event an event
433 void mlt_events_wait_for( mlt_properties
this, mlt_event event
)
437 condition_pair
*pair
= event
->service
;
438 pthread_cond_wait( &pair
->cond
, &pair
->mutex
);
442 /** Cleanup after waiting for an event.
444 * \public \memberof mlt_events_struct
445 * \param this a properties list
446 * \param event an event
449 void mlt_events_close_wait_for( mlt_properties
this, mlt_event event
)
453 condition_pair
*pair
= event
->service
;
456 pthread_mutex_unlock( &pair
->mutex
);
457 pthread_mutex_destroy( &pair
->mutex
);
458 pthread_cond_destroy( &pair
->cond
);
462 /** Fetch the events object.
464 * \private \memberof mlt_events_struct
465 * \param this a properties list
466 * \return an events object
469 static mlt_events
mlt_events_fetch( mlt_properties
this )
471 mlt_events events
= NULL
;
473 events
= mlt_properties_get_data( this, "_events", NULL
);
477 /** Store the events object.
479 * \private \memberof mlt_events_struct
480 * \param this a properties list
481 * \param events an events object
484 static void mlt_events_store( mlt_properties
this, mlt_events events
)
486 if ( this != NULL
&& events
!= NULL
)
487 mlt_properties_set_data( this, "_events", events
, 0, ( mlt_destructor
)mlt_events_close
, NULL
);
490 /** Close the events object.
492 * \private \memberof mlt_events_struct
493 * \param events an events object
496 static void mlt_events_close( mlt_events events
)
498 if ( events
!= NULL
)
500 mlt_properties_close( events
->list
);