]> git.sesse.net Git - mlt/blob - src/framework/mlt_events.c
First draft of event handling
[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 program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program 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
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * 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
25 #include "mlt_properties.h"
26 #include "mlt_events.h"
27
28 /** Memory leak checks.
29 */
30
31 //#define _MLT_EVENT_CHECKS_
32
33 #ifdef _MLT_EVENT_CHECKS_
34 static int events_created = 0;
35 static int events_destroyed = 0;
36 #endif
37
38 struct mlt_events_struct
39 {
40         mlt_properties owner;
41         mlt_properties list;
42 };
43
44 typedef struct mlt_events_struct *mlt_events;
45
46 struct mlt_event_struct
47 {
48         mlt_events owner;
49         int ref_count;
50         int block_count;
51         mlt_listener listener;
52         void *service;
53 };
54
55 /** Increment the reference count on this event.
56 */
57
58 void mlt_event_inc_ref( mlt_event this )
59 {
60         if ( this != NULL && this->owner != NULL )
61                 this->ref_count ++;
62 }
63
64 /** Increment the block count on this event.
65 */
66
67 void mlt_event_block( mlt_event this )
68 {
69         if ( this != NULL && this->owner != NULL )
70                 this->block_count ++;
71 }
72
73 /** Decrement the block count on this event.
74 */
75
76 void mlt_event_unblock( mlt_event this )
77 {
78         if ( this != NULL && this->owner != NULL )
79                 this->block_count --;
80 }
81
82 /** Close this event.
83 */
84
85 void mlt_event_close( mlt_event this )
86 {
87         if ( this != NULL && this->owner != NULL )
88         {
89                 if ( -- this->ref_count == 1 )
90                         this->owner = NULL;
91                 if ( this->ref_count <= 0 )
92                 {
93 #ifdef _MLT_EVENT_CHECKS_
94                         events_destroyed ++;
95                         fprintf( stderr, "Events created %d, destroyed %d\n", events_created, events_destroyed );
96 #endif
97                         free( this );
98                 }
99         }
100 }
101
102 /** Forward declaration to private functions.
103 */
104
105 static mlt_events mlt_events_fetch( mlt_properties );
106 static void mlt_events_store( mlt_properties, mlt_events );
107 static void mlt_events_close( mlt_events );
108
109 /** Initialise the events structure.
110 */
111
112 void mlt_events_init( mlt_properties this )
113 {
114         mlt_events events = mlt_events_fetch( this );
115         if ( events == NULL )
116         {
117                 events = malloc( sizeof( struct mlt_events_struct ) );
118                 events->list = mlt_properties_new( );
119                 mlt_events_store( this, events );
120         }
121 }
122
123 /** Register an event and transmitter.
124 */
125
126 int mlt_events_register( mlt_properties this, char *id, mlt_transmitter transmitter )
127 {
128         int error = 1;
129         mlt_events events = mlt_events_fetch( this );
130         if ( events != NULL )
131         {
132                 mlt_properties list = events->list;
133                 char temp[ 128 ];
134                 error = mlt_properties_set_data( list, id, transmitter, 0, NULL, NULL );
135                 sprintf( temp, "list:%s", id );
136                 if ( mlt_properties_get_data( list, temp, NULL ) == NULL )
137                         mlt_properties_set_data( list, temp, mlt_properties_new( ), 0, ( mlt_destructor )mlt_properties_close, NULL );
138         }
139         return error;
140 }
141
142 /** Fire an event.
143 */
144
145 void mlt_events_fire( mlt_properties this, char *id, ... )
146 {
147         mlt_events events = mlt_events_fetch( this );
148         if ( events != NULL )
149         {
150                 int i = 0;
151                 va_list alist;
152                 void *args[ 10 ];
153                 mlt_properties list = events->list;
154                 mlt_properties listeners = NULL;
155                 char temp[ 128 ];
156                 mlt_transmitter transmitter = mlt_properties_get_data( list, id, NULL );
157                 sprintf( temp, "list:%s", id );
158                 listeners = mlt_properties_get_data( list, temp, NULL );
159
160                 va_start( alist, id );
161                 do
162                         args[ i ] = va_arg( alist, void * );
163                 while( args[ i ++ ] != NULL );
164                 va_end( alist );
165
166                 if ( listeners != NULL )
167                 {
168                         for ( i = 0; i < mlt_properties_count( listeners ); i ++ )
169                         {
170                                 mlt_event event = mlt_properties_get_data_at( listeners, i, NULL );
171                                 if ( event != NULL && event->owner != NULL && event->block_count == 0 )
172                                 {
173                                         if ( transmitter != NULL )
174                                                 transmitter( event->listener, event->owner, event->service, args );
175                                         else
176                                                 event->listener( event->owner, event->service );
177                                 }
178                         }
179                 }
180         }
181 }
182
183 /** Register a listener.
184 */
185
186 mlt_event mlt_events_listen( mlt_properties this, void *service, char *id, mlt_listener listener )
187 {
188         mlt_event event = NULL;
189         mlt_events events = mlt_events_fetch( this );
190         if ( events != NULL )
191         {
192                 mlt_properties list = events->list;
193                 mlt_properties listeners = NULL;
194                 char temp[ 128 ];
195                 sprintf( temp, "list:%s", id );
196                 listeners = mlt_properties_get_data( list, temp, NULL );
197                 if ( listeners != NULL )
198                 {
199                         int first_null = -1;
200                         int i = 0;
201                         for ( i = 0; event == NULL && i < mlt_properties_count( listeners ); i ++ )
202                         {
203                                 mlt_event entry = mlt_properties_get_data_at( listeners, i, NULL );
204                                 if ( entry != NULL && entry->owner != NULL )
205                                 {
206                                         if ( entry->service == service && entry->listener == listener )
207                                                 event = entry;
208                                 }
209                                 else if ( ( entry == NULL || entry->owner == NULL ) && first_null == -1 )
210                                 {
211                                         first_null = i;
212                                 }
213                         }
214
215                         if ( event == NULL )
216                         {
217                                 event = malloc( sizeof( struct mlt_event_struct ) );
218                                 if ( event != NULL )
219                                 {
220 #ifdef _MLT_EVENT_CHECKS_
221                                         events_created ++;
222 #endif
223                                         sprintf( temp, "%d", first_null == -1 ? mlt_properties_count( listeners ) : first_null );
224                                         event->owner = events;
225                                         event->ref_count = 0;
226                                         event->block_count = 0;
227                                         event->listener = listener;
228                                         event->service = service;
229                                         mlt_properties_set_data( listeners, temp, event, 0, ( mlt_destructor )mlt_event_close, NULL );
230                                 }
231                         }
232
233                         if ( event != NULL )
234                                 mlt_event_inc_ref( event );
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 /** Fetch the events object.
323 */
324
325 static mlt_events mlt_events_fetch( mlt_properties this )
326 {
327         mlt_events events = NULL;
328         if ( this != NULL )
329                 events = mlt_properties_get_data( this, "_events", NULL );
330         return events;
331 }
332
333 /** Store the events object.
334 */
335
336 static void mlt_events_store( mlt_properties this, mlt_events events )
337 {
338         if ( this != NULL && events != NULL )
339                 mlt_properties_set_data( this, "_events", events, 0, ( mlt_destructor )mlt_events_close, NULL );
340 }
341
342 /** Close the events object.
343 */
344
345 static void mlt_events_close( mlt_events events )
346 {
347         if ( events != NULL )
348         {
349                 mlt_properties_close( events->list );
350                 free( events );
351         }
352 }
353