diff options
Diffstat (limited to 'osdep/macosx_application.m')
-rw-r--r-- | osdep/macosx_application.m | 200 |
1 files changed, 142 insertions, 58 deletions
diff --git a/osdep/macosx_application.m b/osdep/macosx_application.m index e57b6545b0..1329091e12 100644 --- a/osdep/macosx_application.m +++ b/osdep/macosx_application.m @@ -20,15 +20,11 @@ #include "talloc.h" #include "core/mp_msg.h" -#include "core/mp_fifo.h" #include "core/input/input.h" #include "core/input/keycodes.h" #include "osdep/macosx_application_objc.h" -#include "video/out/osx_common.h" -static Application *app; -static NSAutoreleasePool *pool; static pthread_t playback_thread_id; @interface Application (PrivateMethods) @@ -50,6 +46,67 @@ static pthread_t playback_thread_id; - (void)setAppleMenu:(NSMenu *)aMenu; @end +@implementation InputQueue { + NSMutableArray *_fifo; +} + +- (id)init +{ + if (self = [super init]) { + self->_fifo = [[NSMutableArray alloc] init]; + } + + return self; +} + +- (void)push:(int)keycode +{ + @synchronized (_fifo) { + [_fifo addObject:[NSNumber numberWithInt:keycode]]; + } +} + +- (int)pop +{ + int r = -1; + + @synchronized (_fifo) { + if ([_fifo count] > 0) { + r = [[_fifo objectAtIndex:0] intValue]; + [_fifo removeObjectAtIndex:0]; + } + } + + return r; +} + +- (void)dealloc +{ + [self->_fifo release]; + [super dealloc]; +} +@end + +Application *mpv_shared_app(void) +{ + return (Application *)[Application sharedApplication]; +} + +static NSString *escape_loadfile_name(NSString *input) +{ + NSArray *mappings = @[ + @{ @"in": @"\\", @"out": @"\\\\" }, + @{ @"in": @"\"", @"out": @"\\\"" }, + ]; + + for (NSDictionary *mapping in mappings) { + input = [input stringByReplacingOccurrencesOfString:mapping[@"in"] + withString:mapping[@"out"]]; + } + + return input; +} + @implementation Application @synthesize files = _files; @synthesize argumentsList = _arguments_list; @@ -57,15 +114,45 @@ static pthread_t playback_thread_id; @synthesize inputContext = _input_context; @synthesize keyFIFO = _key_fifo; +@synthesize iqueue = _iqueue; +@synthesize eventsResponder = _events_responder; @synthesize menuItems = _menu_items; +- (void)sendEvent:(NSEvent *)event +{ + if ([event type] == NSSystemDefined && [event subtype] == 8) { + // It's a media key! Handle it specially. The magic numbers are reverse + // engineered and found on several blog posts. Unfortunately there is + // no public API for this. F-bomb. + int code = (([event data1] & 0xFFFF0000) >> 16); + int flags = ([event data1] & 0x0000FFFF); + int down = (((flags & 0xFF00) >> 8)) == 0xA; + + if (down) + [self.eventsResponder handleMediaKey:code]; + } else { + [super sendEvent:event]; + } + + if (self.inputContext) + mp_input_wakeup(self.inputContext); +} + - (id)init { if (self = [super init]) { self.menuItems = [[[NSMutableDictionary alloc] init] autorelease]; self.files = nil; self.argumentsList = [[[NSMutableArray alloc] init] autorelease]; + self.iqueue = [[[InputQueue alloc] init] autorelease]; + self.eventsResponder = [[[EventsResponder alloc] init] autorelease]; self.willStopOnOpenEvent = NO; + + [NSEvent addLocalMonitorForEventsMatchingMask:NSKeyDownMask + handler:^(NSEvent *event) { + return [self.eventsResponder handleKeyDown:event]; + }]; + } return self; @@ -115,23 +202,23 @@ static pthread_t playback_thread_id; [NSApp setMainMenu:main_menu]; [NSApp setAppleMenu:[self appleMenuWithMainMenu:main_menu]]; - [app mainMenuItemWithParent:main_menu child:[self movieMenu]]; - [app mainMenuItemWithParent:main_menu child:[self windowMenu]]; + [NSApp mainMenuItemWithParent:main_menu child:[self movieMenu]]; + [NSApp mainMenuItemWithParent:main_menu child:[self windowMenu]]; } #undef _R - (void)stopPlayback { - [self stop:"quit"]; + [self stopMPV:"quit"]; } - (void)stopPlaybackAndRememberPosition { - [self stop:"quit_watch_later"]; + [self stopMPV:"quit_watch_later"]; } -- (void)stop:(char *)cmd +- (void)stopMPV:(char *)cmd { if (self.inputContext) { mp_cmd_t *cmdt = mp_input_parse_cmd(bstr0(cmd), ""); @@ -192,6 +279,7 @@ static pthread_t playback_thread_id; - (void)application:(NSApplication *)sender openFiles:(NSArray *)filenames { + Application *app = mpv_shared_app(); NSMutableArray *filesToOpen = [[[NSMutableArray alloc] init] autorelease]; [filenames enumerateObjectsUsingBlock:^(id obj, NSUInteger i, BOOL *_) { @@ -237,44 +325,47 @@ struct playback_thread_ctx { static void *playback_thread(void *ctx_obj) { - struct playback_thread_ctx *ctx = (struct playback_thread_ctx*) ctx_obj; - ctx->mpv_main(*ctx->argc, *ctx->argv); - cocoa_stop_runloop(); - pthread_exit(NULL); + @autoreleasepool { + struct playback_thread_ctx *ctx = (struct playback_thread_ctx*) ctx_obj; + ctx->mpv_main(*ctx->argc, *ctx->argv); + cocoa_stop_runloop(); + pthread_exit(NULL); + } } int cocoa_main(mpv_main_fn mpv_main, int argc, char *argv[]) { - struct playback_thread_ctx ctx = {0}; - ctx.mpv_main = mpv_main; - ctx.argc = &argc; - ctx.argv = &argv; - - init_cocoa_application(); - macosx_finder_args_preinit(&argc, &argv); - pthread_create(&playback_thread_id, NULL, playback_thread, &ctx); - cocoa_run_runloop(); - - // This should never be reached: cocoa_run_runloop blocks until the process - // is quit - mp_msg(MSGT_CPLAYER, MSGL_ERR, "There was either a problem initializing " - "Cocoa or the Runloop was stopped unexpectedly. Please report this " - "issues to a developer.\n"); - pthread_join(playback_thread_id, NULL); - return 1; + @autoreleasepool { + struct playback_thread_ctx ctx = {0}; + ctx.mpv_main = mpv_main; + ctx.argc = &argc; + ctx.argv = &argv; + + init_cocoa_application(); + macosx_finder_args_preinit(&argc, &argv); + pthread_create(&playback_thread_id, NULL, playback_thread, &ctx); + cocoa_run_runloop(); + + // This should never be reached: cocoa_run_runloop blocks until the + // process is quit + mp_msg(MSGT_CPLAYER, MSGL_ERR, "There was either a problem " + "initializing Cocoa or the Runloop was stopped unexpectedly. " + "Please report this issues to a developer.\n"); + pthread_join(playback_thread_id, NULL); + return 1; + } } void cocoa_register_menu_item_action(MPMenuKey key, void* action) { - [app registerSelector:(SEL)action forKey:key]; + [NSApp registerSelector:(SEL)action forKey:key]; } void init_cocoa_application(void) { - NSApp = [NSApplication sharedApplication]; - app = [[Application alloc] init]; - [NSApp setDelegate:app]; - [app initialize_menu]; + NSApp = mpv_shared_app(); + [NSApp setDelegate:NSApp]; + [NSApp initialize_menu]; [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular]; atexit_b(^{ @@ -287,21 +378,10 @@ void init_cocoa_application(void) void terminate_cocoa_application(void) { - [NSApp hide:app]; - [NSApp terminate:app]; -} - -void cocoa_autorelease_pool_alloc(void) -{ - pool = [[NSAutoreleasePool alloc] init]; -} - -void cocoa_autorelease_pool_drain(void) -{ - [pool drain]; + [NSApp hide:NSApp]; + [NSApp terminate:NSApp]; } - void cocoa_run_runloop() { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; @@ -319,8 +399,12 @@ void cocoa_stop_runloop(void) void cocoa_set_input_context(struct input_ctx *input_context) { - [NSApp setDelegate:app]; - app.inputContext = input_context; + mpv_shared_app().inputContext = input_context; +} + +void cocoa_set_key_fifo(struct mp_fifo *key_fifo) +{ + mpv_shared_app().keyFIFO = key_fifo; } void cocoa_post_fake_event(void) @@ -339,7 +423,7 @@ void cocoa_post_fake_event(void) static void macosx_wait_fileopen_events() { - app.willStopOnOpenEvent = YES; + mpv_shared_app().willStopOnOpenEvent = YES; cocoa_run_runloop(); // block until done } @@ -356,19 +440,19 @@ static void macosx_redirect_output_to_logfile(const char *filename) static bool psn_matches_current_process(char *psn_arg_to_check) { ProcessSerialNumber psn; - size_t psn_length = 5+10+1+10; - char psn_arg[psn_length+1]; - GetCurrentProcess(&psn); - snprintf(psn_arg, 5+10+1+10+1, "-psn_%u_%u", - psn.highLongOfPSN, psn.lowLongOfPSN); - psn_arg[psn_length]=0; - return strcmp(psn_arg, psn_arg_to_check) == 0; + NSString *in_psn = [NSString stringWithUTF8String:psn_arg_to_check]; + NSString *real_psn = [NSString stringWithFormat:@"-psn_%u_%u", + psn.highLongOfPSN, psn.lowLongOfPSN]; + + return [real_psn isEqualToString:in_psn]; } void macosx_finder_args_preinit(int *argc, char ***argv) { + Application *app = mpv_shared_app(); + if (*argc==2 && psn_matches_current_process((*argv)[1])) { macosx_redirect_output_to_logfile("mpv"); macosx_wait_fileopen_events(); |