3 * \brief event handling
5 * Copyright (C) 2004-2008 Ushodaya Enterprises Limited
6 * \author Charles Yates <charles.yates@pandora.be>
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.
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.
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
28 #include "mlt_properties.h"
29 #include "mlt_events.h"
31 /* Memory leak checks. */
33 #undef _MLT_EVENT_CHECKS_
35 #ifdef _MLT_EVENT_CHECKS_
36 static int events_created
= 0;
37 static int events_destroyed
= 0;
40 /** \brief Events class
42 * Events provide messages and notifications between services and the application.
43 * A service can register an event and fire/send it upon certain conditions or times.
44 * Likewise, a service or an application can listen/receive specific events on specific
48 struct mlt_events_struct
54 typedef struct mlt_events_struct
*mlt_events
;
56 /** \brief Event class
60 struct mlt_event_struct
65 mlt_listener listener
;
69 /** Increment the reference count on this event.
71 * \public \memberof mlt_event_struct
72 * \param this an event
75 void mlt_event_inc_ref( mlt_event
this )
81 /** Increment the block count on this event.
83 * \public \memberof mlt_event_struct
84 * \param this an event
87 void mlt_event_block( mlt_event
this )
89 if ( this != NULL
&& this->owner
!= NULL
)
93 /** Decrement the block count on this event.
95 * \public \memberof mlt_event_struct
96 * \param this an event
99 void mlt_event_unblock( mlt_event
this )
101 if ( this != NULL
&& this->owner
!= NULL
)
102 this->block_count
--;
105 /** Close this event.
107 * \public \memberof mlt_event_struct
108 * \param this an event
111 void mlt_event_close( mlt_event
this )
115 if ( -- this->ref_count
== 1 )
117 if ( this->ref_count
<= 0 )
119 #ifdef _MLT_EVENT_CHECKS_
120 mlt_log( NULL
, MLT_LOG_DEBUG
, "Events created %d, destroyed %d\n", events_created
, ++events_destroyed
);
127 /* Forward declaration to private functions.
130 static mlt_events
mlt_events_fetch( mlt_properties
);
131 static void mlt_events_store( mlt_properties
, mlt_events
);
132 static void mlt_events_close( mlt_events
);
134 /** Initialise the events structure.
136 * \public \memberof mlt_events_struct
137 * \param this a properties list
140 void mlt_events_init( mlt_properties
this )
142 mlt_events events
= mlt_events_fetch( this );
143 if ( events
== NULL
)
145 events
= malloc( sizeof( struct mlt_events_struct
) );
146 events
->list
= mlt_properties_new( );
147 mlt_events_store( this, events
);
151 /** Register an event and transmitter.
153 * \public \memberof mlt_events_struct
154 * \param this a properties list
155 * \param id the name of an event
156 * \param transmitter the callback function to send an event message
157 * \return true if there was an error
160 int mlt_events_register( mlt_properties
this, char *id
, mlt_transmitter transmitter
)
163 mlt_events events
= mlt_events_fetch( this );
164 if ( events
!= NULL
)
166 mlt_properties list
= events
->list
;
168 error
= mlt_properties_set_data( list
, id
, transmitter
, 0, NULL
, NULL
);
169 sprintf( temp
, "list:%s", id
);
170 if ( mlt_properties_get_data( list
, temp
, NULL
) == NULL
)
171 mlt_properties_set_data( list
, temp
, mlt_properties_new( ), 0, ( mlt_destructor
)mlt_properties_close
, NULL
);
178 * This takes a variable number of arguments to supply to the listener.
180 * \public \memberof mlt_events_struct
181 * \param this a properties list
182 * \param id the name of an event
185 void mlt_events_fire( mlt_properties
this, char *id
, ... )
187 mlt_events events
= mlt_events_fetch( this );
188 if ( events
!= NULL
)
193 mlt_properties list
= events
->list
;
194 mlt_properties listeners
= NULL
;
196 mlt_transmitter transmitter
= mlt_properties_get_data( list
, id
, NULL
);
197 sprintf( temp
, "list:%s", id
);
198 listeners
= mlt_properties_get_data( list
, temp
, NULL
);
200 va_start( alist
, id
);
202 args
[ i
] = va_arg( alist
, void * );
203 while( args
[ i
++ ] != NULL
);
206 if ( listeners
!= NULL
)
208 for ( i
= 0; i
< mlt_properties_count( listeners
); i
++ )
210 mlt_event event
= mlt_properties_get_data_at( listeners
, i
, NULL
);
211 if ( event
!= NULL
&& event
->owner
!= NULL
&& event
->block_count
== 0 )
213 if ( transmitter
!= NULL
)
214 transmitter( event
->listener
, event
->owner
, event
->service
, args
);
216 event
->listener( event
->owner
, event
->service
);
223 /** Register a listener.
225 * \public \memberof mlt_events_struct
226 * \param this a properties list
227 * \param service an opaque pointer
228 * \param id the name of the event to listen for
229 * \param listener the callback to receive an event message
233 mlt_event
mlt_events_listen( mlt_properties
this, void *service
, char *id
, mlt_listener listener
)
235 mlt_event event
= NULL
;
236 mlt_events events
= mlt_events_fetch( this );
237 if ( events
!= NULL
)
239 mlt_properties list
= events
->list
;
240 mlt_properties listeners
= NULL
;
242 sprintf( temp
, "list:%s", id
);
243 listeners
= mlt_properties_get_data( list
, temp
, NULL
);
244 if ( listeners
!= NULL
)
248 for ( i
= 0; event
== NULL
&& i
< mlt_properties_count( listeners
); i
++ )
250 mlt_event entry
= mlt_properties_get_data_at( listeners
, i
, NULL
);
251 if ( entry
!= NULL
&& entry
->owner
!= NULL
)
253 if ( entry
->service
== service
&& entry
->listener
== listener
)
256 else if ( ( entry
== NULL
|| entry
->owner
== NULL
) && first_null
== -1 )
264 event
= malloc( sizeof( struct mlt_event_struct
) );
267 #ifdef _MLT_EVENT_CHECKS_
270 sprintf( temp
, "%d", first_null
== -1 ?
mlt_properties_count( listeners
) : first_null
);
271 event
->owner
= events
;
272 event
->ref_count
= 0;
273 event
->block_count
= 0;
274 event
->listener
= listener
;
275 event
->service
= service
;
276 mlt_properties_set_data( listeners
, temp
, event
, 0, ( mlt_destructor
)mlt_event_close
, NULL
);
277 mlt_event_inc_ref( event
);
286 /** Block all events for a given service.
288 * \public \memberof mlt_events_struct
289 * \param this a properties list
290 * \param service an opaque pointer
293 void mlt_events_block( mlt_properties
this, void *service
)
295 mlt_events events
= mlt_events_fetch( this );
296 if ( events
!= NULL
)
299 mlt_properties list
= events
->list
;
300 for ( j
= 0; j
< mlt_properties_count( list
); j
++ )
302 char *temp
= mlt_properties_get_name( list
, j
);
303 if ( !strncmp( temp
, "list:", 5 ) )
305 mlt_properties listeners
= mlt_properties_get_data( list
, temp
, NULL
);
306 for ( i
= 0; i
< mlt_properties_count( listeners
); i
++ )
308 mlt_event entry
= mlt_properties_get_data_at( listeners
, i
, NULL
);
309 if ( entry
!= NULL
&& entry
->service
== service
)
310 mlt_event_block( entry
);
317 /** Unblock all events for a given service.
319 * \public \memberof mlt_events_struct
320 * \param this a properties list
321 * \param service an opaque pointer
324 void mlt_events_unblock( mlt_properties
this, void *service
)
326 mlt_events events
= mlt_events_fetch( this );
327 if ( events
!= NULL
)
330 mlt_properties list
= events
->list
;
331 for ( j
= 0; j
< mlt_properties_count( list
); j
++ )
333 char *temp
= mlt_properties_get_name( list
, j
);
334 if ( !strncmp( temp
, "list:", 5 ) )
336 mlt_properties listeners
= mlt_properties_get_data( list
, temp
, NULL
);
337 for ( i
= 0; i
< mlt_properties_count( listeners
); i
++ )
339 mlt_event entry
= mlt_properties_get_data_at( listeners
, i
, NULL
);
340 if ( entry
!= NULL
&& entry
->service
== service
)
341 mlt_event_unblock( entry
);
348 /** Disconnect all events for a given service.
350 * \public \memberof mlt_events_struct
351 * \param this a properties list
352 * \param service an opaque pointer
355 void mlt_events_disconnect( mlt_properties
this, void *service
)
357 mlt_events events
= mlt_events_fetch( this );
358 if ( events
!= NULL
)
361 mlt_properties list
= events
->list
;
362 for ( j
= 0; j
< mlt_properties_count( list
); j
++ )
364 char *temp
= mlt_properties_get_name( list
, j
);
365 if ( !strncmp( temp
, "list:", 5 ) )
367 mlt_properties listeners
= mlt_properties_get_data( list
, temp
, NULL
);
368 for ( i
= 0; i
< mlt_properties_count( listeners
); i
++ )
370 mlt_event entry
= mlt_properties_get_data_at( listeners
, i
, NULL
);
371 char *name
= mlt_properties_get_name( listeners
, i
);
372 if ( entry
!= NULL
&& entry
->service
== service
)
373 mlt_properties_set_data( listeners
, name
, NULL
, 0, NULL
, NULL
);
380 /** \brief private to mlt_events_struct, used by mlt_events_wait_for() */
386 pthread_mutex_t mutex
;
390 /** The event listener callback for the wait functions.
392 * \private \memberof mlt_events_struct
393 * \param this a properties list
394 * \param pair a condition pair
397 static void mlt_events_listen_for( mlt_properties
this, condition_pair
*pair
)
399 pthread_mutex_lock( &pair
->mutex
);
400 if ( pair
->done
== 0 )
402 pthread_cond_signal( &pair
->cond
);
403 pthread_mutex_unlock( &pair
->mutex
);
407 /** Prepare to wait for an event.
409 * \public \memberof mlt_events_struct
410 * \param this a properties list
411 * \param id the name of the event to wait for
415 mlt_event
mlt_events_setup_wait_for( mlt_properties
this, char *id
)
417 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( this, pair
, id
, ( mlt_listener
)mlt_events_listen_for
);
425 /** Wait for an event.
427 * \public \memberof mlt_events_struct
428 * \param this a properties list
429 * \param event an event
432 void mlt_events_wait_for( mlt_properties
this, 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 this a properties list
445 * \param event an event
448 void mlt_events_close_wait_for( mlt_properties
this, mlt_event event
)
452 condition_pair
*pair
= event
->service
;
455 pthread_mutex_unlock( &pair
->mutex
);
456 pthread_mutex_destroy( &pair
->mutex
);
457 pthread_cond_destroy( &pair
->cond
);
461 /** Fetch the events object.
463 * \private \memberof mlt_events_struct
464 * \param this a properties list
465 * \return an events object
468 static mlt_events
mlt_events_fetch( mlt_properties
this )
470 mlt_events events
= NULL
;
472 events
= mlt_properties_get_data( this, "_events", NULL
);
476 /** Store the events object.
478 * \private \memberof mlt_events_struct
479 * \param this a properties list
480 * \param events an events object
483 static void mlt_events_store( mlt_properties
this, mlt_events events
)
485 if ( this != NULL
&& events
!= NULL
)
486 mlt_properties_set_data( this, "_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
);