MacOSX/Framework/VLCEventManager.m: Remove unuseful ;.
[vlc.git] / extras / MacOSX / Framework / Sources / VLCEventManager.m
1 /*****************************************************************************
2  * VLCTime.h: VLC.framework VLCTime implementation
3  *****************************************************************************
4  * Copyright (C) 2007 Pierre d'Herbemont
5  * Copyright (C) 2007 the VideoLAN team
6  * $Id$
7  *
8  * Authors: Pierre d'Herbemont <pdherbemont # videolan.org>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24
25 #import "VLCEventManager.h"
26 #import <pthread.h>
27
28 static VLCEventManager * defaultManager = NULL;
29
30 enum message_type_t
31 {
32     VLCNotification,
33     VLCObjectMethodWithObjectArg
34 };
35
36 struct message {
37     id target;
38     SEL sel;
39     union u
40     {
41         NSString * name;
42         id object;
43     } u;
44     enum message_type_t type;
45 };
46
47 @interface VLCEventManager (Private)
48 - (void)callDelegateOfObjectAndSendNotificationWithArgs:(NSData*)data;
49 - (void)callObjectMethodWithArgs:(NSData*)data;
50 - (void)callDelegateOfObject:(id) aTarget withDelegateMethod:(SEL)aSelector withNotificationName: (NSString *)aNotificationName;
51 - (pthread_cond_t *)signalData;
52 - (pthread_mutex_t *)queueLock;
53 - (NSMutableArray *)messageQueue;
54 @end
55
56 static void * EventDispatcherMainLoop(void * user_data)
57 {
58     VLCEventManager * self = user_data;
59
60     for(;;)
61     {
62         NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
63         struct message * message, * message_newer = NULL;
64         NSData *dataMessage;
65         int i;
66
67         /* Wait for some data */
68         pthread_mutex_lock( [self queueLock] );
69         
70         /* Wait until we have something on the queue */
71         while([[self messageQueue] count] <= 0 )
72         {
73             pthread_cond_wait( [self signalData], [self queueLock] );
74         }
75         message = (struct message *)[(NSData *)[[self messageQueue] lastObject] bytes];
76         
77         /* Don't send the same notification twice */
78         if( message->type == VLCNotification )
79         {
80             for( i = 0; i < [[self messageQueue] count]-1; i++ )
81             {
82                 message_newer = (struct message *)[(NSData *)[[self messageQueue] objectAtIndex: i] bytes];
83                 if( message_newer->type != VLCNotification )
84                     continue;
85                 
86                 if( message_newer->target == message->target && message_newer->target == message->target && [message_newer->u.name isEqualToString:message->u.name] )
87                 {
88                     [message_newer->target release];
89                     [message->u.name release];
90                     [[self messageQueue] removeObjectAtIndex: i];
91                     i--;
92                 }
93             }
94         }
95
96         dataMessage = [[self messageQueue] lastObject];
97         
98         pthread_mutex_unlock( [self queueLock] );
99         
100         if( message->type == VLCNotification )
101             [self performSelectorOnMainThread:@selector(callDelegateOfObjectAndSendNotificationWithArgs:) withObject:[dataMessage retain] waitUntilDone: NO];
102         else
103             [self performSelectorOnMainThread:@selector(callObjectMethodWithArgs:) withObject:[dataMessage retain] waitUntilDone: NO];
104
105         pthread_mutex_lock( [self queueLock] );
106         [[self messageQueue] removeLastObject];
107         pthread_mutex_unlock( [self queueLock] );
108     
109         [pool release];
110     }
111     return nil;
112 }
113
114 @implementation VLCEventManager
115 + (id)sharedManager
116 {
117     /* We do want a lock here to avoid leaks */
118     if ( !defaultManager )
119     {
120         defaultManager = [[VLCEventManager alloc] init];
121     }
122
123     return defaultManager;
124 }
125
126 - (id)init
127 {
128     if( self = [super init] )
129     {
130         pthread_mutex_init( &queueLock, NULL );
131         pthread_cond_init( &signalData, NULL );
132         pthread_create( &dispatcherThread, NULL, EventDispatcherMainLoop, self );
133         messageQueue = [[NSMutableArray alloc] initWithCapacity:10];
134     }
135     return self;
136 }
137
138 - (void)dealloc
139 {
140     pthread_kill( dispatcherThread, SIGKILL );
141     pthread_join( dispatcherThread, NULL );
142
143     [messageQueue release];
144     [super dealloc];
145 }
146
147 - (void)callOnMainThreadDelegateOfObject:(id)aTarget withDelegateMethod:(SEL)aSelector withNotificationName: (NSString *)aNotificationName
148 {
149     NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
150     
151     struct message message = 
152     { 
153         [aTarget retain], 
154         aSelector, 
155         [aNotificationName retain], 
156         VLCNotification 
157     };
158     
159     pthread_mutex_lock( [self queueLock] );
160     [[self messageQueue] insertObject:[NSData dataWithBytes:&message length:sizeof(struct message)] atIndex:0];
161     pthread_cond_signal( [self signalData] );
162     pthread_mutex_unlock( [self queueLock] );
163     
164     [pool release];
165 }
166
167 - (void)callOnMainThreadObject:(id)aTarget withMethod:(SEL)aSelector withArgumentAsObject: (id)arg
168 {
169     NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
170
171     struct message message = 
172     { 
173         [aTarget retain], 
174         aSelector, 
175         [arg retain], 
176         VLCObjectMethodWithObjectArg 
177     };
178     
179     pthread_mutex_lock( [self queueLock] );
180     [[self messageQueue] insertObject:[NSData dataWithBytes:&message length:sizeof(struct message)] atIndex:0];
181     pthread_cond_signal( [self signalData] );
182     pthread_mutex_unlock( [self queueLock] );
183     
184     [pool release];
185 }
186 @end
187
188 @implementation VLCEventManager (Private)
189 - (void)callDelegateOfObjectAndSendNotificationWithArgs:(NSData*)data
190 {
191     struct message * message = (struct message *)[data bytes];
192
193     [self callDelegateOfObject:message->target withDelegateMethod:message->sel withNotificationName:message->u.name];
194     [message->u.name release];
195     [message->target release];
196     [data release];
197 }
198
199 - (void)callObjectMethodWithArgs:(NSData*)data
200 {
201     struct message * message = (struct message *)[data bytes];
202     void (*method)(id, SEL, id) = (void (*)(id, SEL, id))[message->target methodForSelector: message->sel];
203
204     method( message->target, message->sel, message->u.object);
205     [message->u.object release];
206     [message->target release];
207     [data release];
208 }
209
210 - (NSMutableArray *)messageQueue
211 {
212     return messageQueue;
213 }
214
215 - (pthread_cond_t *)signalData
216 {
217     return &signalData;
218 }
219
220 - (pthread_mutex_t *)queueLock
221 {
222     return &queueLock;
223 }
224
225 - (void)callDelegateOfObject:(id) aTarget withDelegateMethod:(SEL)aSelector withNotificationName: (NSString *)aNotificationName
226 {
227 //    [[NSNotificationCenter defaultCenter] postNotification: [NSNotification notificationWithName:aNotificationName object:aTarget]];
228
229     if (![aTarget delegate] || ![[aTarget delegate] respondsToSelector: aSelector])
230         return;
231
232     void (*method)(id, SEL, id) = (void (*)(id, SEL, id))[[aTarget delegate] methodForSelector: aSelector];
233     method( [aTarget delegate], aSelector, [NSNotification notificationWithName:aNotificationName object:aTarget]);
234 }
235 @end