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