#import "VLCEventManager.h"
#import <pthread.h>
-static VLCEventManager * defaultManager = NULL;
-
-enum message_type_t
+/**
+ * Defines the type of interthread message on the queue.
+ */
+typedef enum
{
- VLCNotification,
- VLCObjectMethodWithObjectArg,
- VLCObjectMethodWithArrayArg
-};
-
-struct message {
- id target;
- SEL sel;
- union u
+ VLCNotification, //< Standard NSNotification.
+ VLCObjectMethodWithObjectArg, //< Method with an object argument.
+ VLCObjectMethodWithArrayArg //< Method with an array argument.
+} message_type_t;
+
+/**
+ * Data structured used to enqueue messages onto the queue.
+ */
+typedef struct {
+ id target; //< Target object that should receive the message (retained until method is called).
+ SEL sel; //< A selector that identifies the message to be sent to the target.
+ union u //< Object could either be a VLCNotification or other.
{
- NSString * name;
- id object;
+ NSString * name; //< Name to be used for NSNotification
+ id object; //< Object argument to pass to the target via the selector.
} u;
- enum message_type_t type;
-};
+ message_type_t type; //< Type of queued message.
+} message_t;
@interface VLCEventManager (Private)
- (void)callDelegateOfObjectAndSendNotificationWithArgs:(NSData*)data;
- (void)callObjectMethodWithArgs:(NSData*)data;
-- (void)callDelegateOfObject:(id) aTarget withDelegateMethod:(SEL)aSelector withNotificationName: (NSString *)aNotificationName;
+- (void)callDelegateOfObject:(id) aTarget withDelegateMethod:(SEL)aSelector withNotificationName:(NSString *)aNotificationName;
- (pthread_cond_t *)signalData;
- (pthread_mutex_t *)queueLock;
- (NSMutableArray *)messageQueue;
@end
+/**
+ * Provides a function for the main entry point for the dispatch thread. It dispatches any messages that is queued.
+ * \param user_data Pointer to the VLCEventManager instance that instiated this thread.
+ */
static void * EventDispatcherMainLoop(void * user_data)
{
VLCEventManager * self = user_data;
for(;;)
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
- struct message * message, * message_newer = NULL;
+ message_t * message, * message_newer = NULL;
NSData * dataMessage;
int i;
//if( [[self messageQueue] count] % 100 == 0 || [[self messageQueue] count] < 100 )
// NSLog(@"[EVENT_MANAGER] On the stack we have %d elements", [[self messageQueue] count]);
- message = (struct message *)[(NSData *)[[self messageQueue] lastObject] bytes];
+ /* Get the first object off the queue. */
+ dataMessage = [[[self messageQueue] lastObject] retain]; // Released in 'call'
+ [[self messageQueue] removeLastObject];
+ message = (message_t *)[dataMessage bytes];
- /* Don't send the same notification twice */
+ /* Remove duplicate notifications. */
if( message->type == VLCNotification )
{
- for( i = 0; i < [[self messageQueue] count]-1; i++ )
+ for( i = [[self messageQueue] count]-1; i >= 0; i-- )
{
- message_newer = (struct message *)[(NSData *)[[self messageQueue] objectAtIndex:i] bytes];
+ message_newer = (message_t *)[(NSData *)[[self messageQueue] objectAtIndex:i] bytes];
if( message_newer->type == VLCNotification &&
message_newer->target == message->target &&
[message_newer->u.name isEqualToString:message->u.name] )
[message_newer->target release];
[message_newer->u.name release];
[[self messageQueue] removeObjectAtIndex:i];
- i--;
- continue;
}
}
}
else if( message->type == VLCObjectMethodWithArrayArg )
{
NSMutableArray * newArg = nil;
+
/* Collapse messages that takes array arg by sending one bigger array */
- for( i = [[self messageQueue] count]-2; i >= 0; i-- )
+ for( i = [[self messageQueue] count]-1; i >= 0; i-- )
{
- message_newer = (struct message *)[(NSData *)[[self messageQueue] objectAtIndex: i] bytes];
+ message_newer = (message_t *)[(NSData *)[[self messageQueue] objectAtIndex: i] bytes];
if( message_newer->type == VLCObjectMethodWithArrayArg &&
message_newer->target == message->target &&
message_newer->sel == message->sel )
{
if(!newArg)
+ {
newArg = [NSMutableArray arrayWithArray:message->u.object];
+ [message->u.object release];
+ }
+
[newArg addObjectsFromArray:message_newer->u.object];
[message_newer->target release];
[message_newer->u.object release];
- [[self messageQueue] removeObjectAtIndex: i];
- continue;
+ [[self messageQueue] removeObjectAtIndex:i];
}
/* It should be a good idea not to collapse event, with other kind of event in-between
* Ignore for now only if target is the same */
- else if( message_newer->target == message->target )
+ else if( message_newer->target != message->target )
break;
}
+
if( newArg )
- {
- [message->u.object release];
message->u.object = [newArg retain];
- [newArg retain];
- }
}
-
- dataMessage = [[self messageQueue] lastObject];
pthread_mutex_unlock( [self queueLock] );
if( message->type == VLCNotification )
- [self performSelectorOnMainThread:@selector(callDelegateOfObjectAndSendNotificationWithArgs:) withObject:[dataMessage retain] /* released in the call */ waitUntilDone: NO];
+ [self performSelectorOnMainThread:@selector(callDelegateOfObjectAndSendNotificationWithArgs:)
+ withObject:dataMessage
+ waitUntilDone: NO];
else
- [self performSelectorOnMainThread:@selector(callObjectMethodWithArgs:) withObject:[dataMessage retain] /* released in the call */ waitUntilDone: YES];
+ [self performSelectorOnMainThread:@selector(callObjectMethodWithArgs:)
+ withObject:dataMessage
+ waitUntilDone: YES];
- pthread_mutex_lock( [self queueLock] );
- [[self messageQueue] removeLastObject];
- pthread_mutex_unlock( [self queueLock] );
-
[pool release];
}
return nil;
@implementation VLCEventManager
+ (id)sharedManager
{
+ static VLCEventManager * defaultManager = NULL;
+
/* We do want a lock here to avoid leaks */
if ( !defaultManager )
{
- (void)callOnMainThreadDelegateOfObject:(id)aTarget withDelegateMethod:(SEL)aSelector withNotificationName: (NSString *)aNotificationName
{
- NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
+// NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
- struct message message =
+ message_t message =
{
[aTarget retain],
aSelector,
VLCNotification
};
- if([NSThread isMainThread])
- {
- [self callDelegateOfObjectAndSendNotificationWithArgs:[[NSData dataWithBytes:&message length:sizeof(struct message)] retain] /* released in the call */];
- return;
- }
-
- // pthread_mutex_lock( [self queueLock] );
- // [[self messageQueue] insertObject:[NSData dataWithBytes:&message length:sizeof(struct message)] atIndex:0];
- // pthread_cond_signal( [self signalData] );
- // pthread_mutex_unlock( [self queueLock] );
+// if( [NSThread isMainThread] )
+// {
+ [self callDelegateOfObjectAndSendNotificationWithArgs:[[NSData dataWithBytes:&message length:sizeof(message_t)] retain] /* released in the call */];
+// }
+// else
+// {
+// pthread_mutex_lock( [self queueLock] );
+// [[self messageQueue] insertObject:[NSData dataWithBytes:&message length:sizeof(message_t)] atIndex:0];
+// pthread_cond_signal( [self signalData] );
+// pthread_mutex_unlock( [self queueLock] );
+// }
[pool release];
}
- (void)callOnMainThreadObject:(id)aTarget withMethod:(SEL)aSelector withArgumentAsObject: (id)arg
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
- struct message message =
+ message_t message =
{
[aTarget retain],
aSelector,
};
pthread_mutex_lock( [self queueLock] );
- [[self messageQueue] insertObject:[NSData dataWithBytes:&message length:sizeof(struct message)] atIndex:0];
+ [[self messageQueue] insertObject:[NSData dataWithBytes:&message length:sizeof(message_t)] atIndex:0];
pthread_cond_signal( [self signalData] );
pthread_mutex_unlock( [self queueLock] );
@implementation VLCEventManager (Private)
- (void)callDelegateOfObjectAndSendNotificationWithArgs:(NSData*)data
{
- struct message * message = (struct message *)[data bytes];
+ message_t * message = (message_t *)[data bytes];
[self callDelegateOfObject:message->target withDelegateMethod:message->sel withNotificationName:message->u.name];
[message->u.name release];
- (void)callObjectMethodWithArgs:(NSData*)data
{
- struct message * message = (struct message *)[data bytes];
+ message_t * message = (message_t *)[data bytes];
void (*method)(id, SEL, id) = (void (*)(id, SEL, id))[message->target methodForSelector: message->sel];
method( message->target, message->sel, message->u.object);
[data release];
}
+- (void)callDelegateOfObject:(id) aTarget withDelegateMethod:(SEL)aSelector withNotificationName: (NSString *)aNotificationName
+{
+ // [[NSNotificationCenter defaultCenter] postNotification: [NSNotification notificationWithName:aNotificationName object:aTarget]];
+
+ if (![aTarget delegate] || ![[aTarget delegate] respondsToSelector:aSelector])
+ return;
+
+ void (*method)(id, SEL, id) = (void (*)(id, SEL, id))[[aTarget delegate] methodForSelector: aSelector];
+ method( [aTarget delegate], aSelector, [NSNotification notificationWithName:aNotificationName object:aTarget]);
+}
+
- (NSMutableArray *)messageQueue
{
return messageQueue;
{
return &queueLock;
}
-
-- (void)callDelegateOfObject:(id) aTarget withDelegateMethod:(SEL)aSelector withNotificationName: (NSString *)aNotificationName
-{
-// [[NSNotificationCenter defaultCenter] postNotification: [NSNotification notificationWithName:aNotificationName object:aTarget]];
-
- if (![aTarget delegate] || ![[aTarget delegate] respondsToSelector: aSelector])
- return;
-
- void (*method)(id, SEL, id) = (void (*)(id, SEL, id))[[aTarget delegate] methodForSelector: aSelector];
- method( [aTarget delegate], aSelector, [NSNotification notificationWithName:aNotificationName object:aTarget]);
-}
@end