X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fgui%2Fmacosx%2Fintf.m;h=3cb3c77339d554924c239ad84807e50fe6908f65;hb=c68b81019c2840eaa9781a4d967bebf36758d888;hp=7d3fc06e582af4d0563f69dea1e408b3ce230198;hpb=b021f08d84b02f9ac672f5af74242d63a2cda970;p=vlc diff --git a/modules/gui/macosx/intf.m b/modules/gui/macosx/intf.m index 7d3fc06e58..3cb3c77339 100644 --- a/modules/gui/macosx/intf.m +++ b/modules/gui/macosx/intf.m @@ -30,7 +30,9 @@ #include /* malloc(), free() */ #include /* for MAXPATHLEN */ #include +#include #include +#include #include /* execl() */ #import "intf.h" @@ -45,15 +47,18 @@ #import "wizard.h" #import "extended.h" #import "bookmarks.h" -#import "interaction.h" +#import "coredialogs.h" #import "embeddedwindow.h" -#import "update.h" #import "AppleRemote.h" #import "eyetv.h" #import "simple_prefs.h" +#ifdef ENABLE_VLM #import "vlm.h" +#endif -#import +#import /* for crashlog send mechanism */ +#import /* for the media key support */ +#import /* we're the update delegate */ /***************************************************************************** * Local prototypes. @@ -65,6 +70,12 @@ static void * ManageThread( void *user_data ); static unichar VLCKeyToCocoa( unsigned int i_key ); static unsigned int VLCModifiersToCocoa( unsigned int i_key ); +static void updateProgressPanel (void *, const char *, float); +static bool checkProgressPanel (void *); +static void destroyProgressPanel (void *); + +static void MsgCallback( msg_cb_data_t *, msg_item_t *, unsigned ); + #pragma mark - #pragma mark VLC Interface Object Callbacks @@ -77,20 +88,16 @@ int OpenIntf ( vlc_object_t *p_this ) p_intf->p_sys = malloc( sizeof( intf_sys_t ) ); if( p_intf->p_sys == NULL ) - { - return( 1 ); - } + return VLC_ENOMEM; memset( p_intf->p_sys, 0, sizeof( *p_intf->p_sys ) ); - p_intf->p_sys->o_pool = [[NSAutoreleasePool alloc] init]; - /* subscribe to LibVLCCore's messages */ p_intf->p_sys->p_sub = msg_Subscribe( p_intf->p_libvlc, MsgCallback, NULL ); p_intf->pf_run = Run; p_intf->b_should_run_on_first_thread = true; - return( 0 ); + return VLC_SUCCESS; } /***************************************************************************** @@ -100,15 +107,14 @@ void CloseIntf ( vlc_object_t *p_this ) { intf_thread_t *p_intf = (intf_thread_t*) p_this; - [p_intf->p_sys->o_pool release]; - free( p_intf->p_sys ); } /***************************************************************************** * Run: main loop *****************************************************************************/ -jmp_buf jmpbuffer; +static NSLock * o_appLock = nil; // controls access to f_appExit +static int f_appExit = 0; // set to 1 when application termination signaled static void Run( intf_thread_t *p_intf ) { @@ -129,17 +135,15 @@ static void Run( intf_thread_t *p_intf ) NSAutoreleasePool * o_pool = [[NSAutoreleasePool alloc] init]; - /* Install a jmpbuffer to where we can go back before the NSApp exit - * see applicationWillTerminate: */ - [NSApplication sharedApplication]; + o_appLock = [[NSLock alloc] init]; + + [VLCApplication sharedApplication]; [[VLCMain sharedInstance] setIntf: p_intf]; [NSBundle loadNibNamed: @"MainMenu" owner: NSApp]; - /* Install a jmpbuffer to where we can go back before the NSApp exit - * see applicationWillTerminate: */ - if(setjmp(jmpbuffer) == 0) - [NSApp run]; + [NSApp run]; + [[VLCMain sharedInstance] applicationWillTerminate:nil]; [o_pool release]; } @@ -156,24 +160,24 @@ static void MsgCallback( msg_cb_data_t *data, msg_item_t *item, unsigned int i ) { int canc = vlc_savecancel(); NSAutoreleasePool * o_pool = [[NSAutoreleasePool alloc] init]; - - NSDictionary *o_dict = [NSDictionary dictionaryWithObjects: - [NSArray arrayWithObjects: - [NSString stringWithUTF8String: item->psz_module], - [NSString stringWithUTF8String: item->psz_msg], - [NSNumber numberWithInt: item->i_type], nil] - forKeys: - [NSArray arrayWithObjects: @"Module", @"Message", @"Type", nil]]; - + + /* this may happen from time to time, let's bail out as info would be useless anyway */ + if( !item->psz_module || !item->psz_msg ) + return; + + NSDictionary *o_dict = [NSDictionary dictionaryWithObjectsAndKeys: + [NSString stringWithUTF8String: item->psz_module], @"Module", + [NSString stringWithUTF8String: item->psz_msg], @"Message", + [NSNumber numberWithInt: item->i_type], @"Type", nil]; + [[NSNotificationCenter defaultCenter] postNotificationName: @"VLCCoreMessageReceived" object: nil userInfo: o_dict]; - + [o_pool release]; vlc_restorecancel( canc ); } - /***************************************************************************** * playlistChanged: Callback triggered by the intf-change playlist * variable, to let the intf update the playlist. @@ -182,10 +186,13 @@ static int PlaylistChanged( vlc_object_t *p_this, const char *psz_variable, vlc_value_t old_val, vlc_value_t new_val, void *param ) { intf_thread_t * p_intf = VLCIntf; - p_intf->p_sys->b_intf_update = true; - p_intf->p_sys->b_playlist_update = true; - p_intf->p_sys->b_playmode_update = true; - p_intf->p_sys->b_current_title_update = true; + if( p_intf && p_intf->p_sys ) + { + p_intf->p_sys->b_intf_update = true; + p_intf->p_sys->b_playlist_update = true; + p_intf->p_sys->b_playmode_update = true; + p_intf->p_sys->b_current_title_update = true; + } return VLC_SUCCESS; } @@ -198,7 +205,8 @@ static int ShowController( vlc_object_t *p_this, const char *psz_variable, vlc_value_t old_val, vlc_value_t new_val, void *param ) { intf_thread_t * p_intf = VLCIntf; - p_intf->p_sys->b_intf_show = true; + if( p_intf && p_intf->p_sys ) + p_intf->p_sys->b_intf_show = true; return VLC_SUCCESS; } @@ -210,29 +218,98 @@ static int FullscreenChanged( vlc_object_t *p_this, const char *psz_variable, vlc_value_t old_val, vlc_value_t new_val, void *param ) { intf_thread_t * p_intf = VLCIntf; - p_intf->p_sys->b_fullscreen_update = true; + if( p_intf && p_intf->p_sys ) + p_intf->p_sys->b_fullscreen_update = true; return VLC_SUCCESS; } /***************************************************************************** - * InteractCallback: Callback triggered by the interaction - * variable, to let the intf display error and interaction dialogs + * DialogCallback: Callback triggered by the "dialog-*" variables + * to let the intf display error and interaction dialogs *****************************************************************************/ -static int InteractCallback( vlc_object_t *p_this, const char *psz_variable, - vlc_value_t old_val, vlc_value_t new_val, void *param ) +static int DialogCallback( vlc_object_t *p_this, const char *type, vlc_value_t previous, vlc_value_t value, void *data ) { NSAutoreleasePool * o_pool = [[NSAutoreleasePool alloc] init]; - VLCMain *interface = (VLCMain *)param; - interaction_dialog_t *p_dialog = (interaction_dialog_t *)(new_val.p_address); - NSValue *o_value = [NSValue valueWithPointer:p_dialog]; - - [[NSNotificationCenter defaultCenter] postNotificationName: @"VLCNewInteractionEventNotification" object:[interface getInteractionList] - userInfo:[NSDictionary dictionaryWithObject:o_value forKey:@"VLCDialogPointer"]]; - + VLCMain *interface = (VLCMain *)data; + + if( [[NSString stringWithUTF8String: type] isEqualToString: @"dialog-progress-bar"] ) + { + /* the progress panel needs to update itself and therefore wants special treatment within this context */ + dialog_progress_bar_t *p_dialog = (dialog_progress_bar_t *)value.p_address; + + p_dialog->pf_update = updateProgressPanel; + p_dialog->pf_check = checkProgressPanel; + p_dialog->pf_destroy = destroyProgressPanel; + p_dialog->p_sys = VLCIntf->p_libvlc; + } + + NSValue *o_value = [NSValue valueWithPointer:value.p_address]; + [[NSNotificationCenter defaultCenter] postNotificationName: @"VLCNewCoreDialogEventNotification" object:[interface coreDialogProvider] userInfo:[NSDictionary dictionaryWithObjectsAndKeys: o_value, @"VLCDialogPointer", [NSString stringWithUTF8String: type], @"VLCDialogType", nil]]; + [o_pool release]; return VLC_SUCCESS; } +void updateProgressPanel (void *priv, const char *text, float value) +{ + NSAutoreleasePool *o_pool = [[NSAutoreleasePool alloc] init]; + + NSString *o_txt; + if( text != NULL ) + o_txt = [NSString stringWithUTF8String: text]; + else + o_txt = @""; + + [[[VLCMain sharedInstance] coreDialogProvider] updateProgressPanelWithText: o_txt andNumber: (double)(value * 1000.)]; + + [o_pool release]; +} + +void destroyProgressPanel (void *priv) +{ + NSAutoreleasePool *o_pool = [[NSAutoreleasePool alloc] init]; + [[[VLCMain sharedInstance] coreDialogProvider] destroyProgressPanel]; + [o_pool release]; +} + +bool checkProgressPanel (void *priv) +{ + NSAutoreleasePool *o_pool = [[NSAutoreleasePool alloc] init]; + return [[[VLCMain sharedInstance] coreDialogProvider] progressCancelled]; + [o_pool release]; +} + +#pragma mark - +#pragma mark Helpers + +input_thread_t *getInput(void) +{ + intf_thread_t *p_intf = VLCIntf; + if (!p_intf) + return NULL; + return pl_CurrentInput(p_intf); +} + +vout_thread_t *getVout(void) +{ + input_thread_t *p_input = getInput(); + if (!p_input) + return NULL; + vout_thread_t *p_vout = input_GetVout(p_input); + vlc_object_release(p_input); + return p_vout; +} + +aout_instance_t *getAout(void) +{ + input_thread_t *p_input = getInput(); + if (!p_input) + return NULL; + aout_instance_t *p_aout = input_GetAout(p_input); + vlc_object_release(p_input); + return p_aout; +} + #pragma mark - #pragma mark Private @@ -265,8 +342,10 @@ static VLCMain *_o_sharedMainInstance = nil; else _o_sharedMainInstance = [super init]; + p_intf = NULL; + o_msg_lock = [[NSLock alloc] init]; - o_msg_arr = [[NSMutableArray arrayWithCapacity: 200] retain]; + o_msg_arr = [[NSMutableArray arrayWithCapacity: 600] retain]; /* subscribe to LibVLC's debug messages as early as possible (for us) */ [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(libvlcMessageReceived:) name: @"VLCCoreMessageReceived" object: nil]; @@ -274,22 +353,17 @@ static VLCMain *_o_sharedMainInstance = nil; o_prefs = nil; o_open = [[VLCOpen alloc] init]; o_wizard = [[VLCWizard alloc] init]; +#ifdef ENABLE_VLM o_vlm = [[VLCVLMController alloc] init]; +#endif o_extended = nil; o_bookmarks = [[VLCBookmarks alloc] init]; o_embedded_list = [[VLCEmbeddedList alloc] init]; - o_interaction_list = [[VLCInteractionList alloc] init]; + o_coredialogs = [[VLCCoreDialogProvider alloc] init]; o_info = [[VLCInfo alloc] init]; -#ifdef UPDATE_CHECK - o_update = [[VLCUpdate alloc] init]; -#endif i_lastShownVolume = -1; - o_remote = [[AppleRemote alloc] init]; - [o_remote setClickCountEnabledButtons: kRemoteButtonPlay]; - [o_remote setDelegate: _o_sharedMainInstance]; - o_eyetv = [[VLCEyeTVController alloc] init]; /* announce our launch to a potential eyetv plugin */ @@ -305,7 +379,7 @@ static VLCMain *_o_sharedMainInstance = nil; p_intf = p_mainintf; } -- (intf_thread_t *)getIntf { +- (intf_thread_t *)intf { return p_intf; } @@ -315,32 +389,11 @@ static VLCMain *_o_sharedMainInstance = nil; playlist_t *p_playlist; vlc_value_t val; - /* Check if we already did this once. Opening the other nibs calls it too, because VLCMain is the owner */ - if( nib_main_loaded ) return; + if( !p_intf ) return; - /* check whether the user runs a valid version of OS X */ - if( MACOS_VERSION < 10.5f ) - { - NSAlert *ourAlert; - int i_returnValue; - NSString *o_blabla; - if( MACOS_VERSION == 10.5f ) - o_blabla = _NS("VLC's last release for your OS is the 0.9 series." ); - else if( MACOS_VERSION == 10.3f ) - o_blabla = _NS("VLC's last release for your OS is VLC 0.8.6i, which is prone to known security issues." ); - else // 10.2 and 10.1, still 3% of the OS X market share - o_blabla = _NS("VLC's last release for your OS is VLC 0.7.2, which is highly out of date and prone to " \ - "known security issues. We recommend you to update your Mac to a modern version of Mac OS X."); - ourAlert = [NSAlert alertWithMessageText: _NS("Your version of Mac OS X is no longer supported") - defaultButton: _NS("Quit") - alternateButton: NULL - otherButton: NULL - informativeTextWithFormat: _NS("VLC media player %s requires Mac OS X 10.5 or higher.\n\n%@"), VLC_Version(), o_blabla]; - [ourAlert setAlertStyle: NSCriticalAlertStyle]; - i_returnValue = [ourAlert runModal]; - [NSApp performSelectorOnMainThread: @selector(terminate:) withObject:nil waitUntilDone:NO]; - return; - } + /* Check if we already did this once. Opening the other nibs calls it too, + because VLCMain is the owner */ + if( nib_main_loaded ) return; [self initStrings]; @@ -372,6 +425,9 @@ static VLCMain *_o_sharedMainInstance = nil; i_key = config_GetInt( p_intf, "key-slower" ); [o_mi_slower setKeyEquivalent: [NSString stringWithFormat:@"%C", VLCKeyToCocoa( i_key )]]; [o_mi_slower setKeyEquivalentModifierMask: VLCModifiersToCocoa(i_key)]; + i_key = config_GetInt( p_intf, "key-rate-normal" ); + [o_mi_normalSpeed setKeyEquivalent: [NSString stringWithFormat:@"%C", VLCKeyToCocoa( i_key )]]; + [o_mi_normalSpeed setKeyEquivalentModifierMask: VLCModifiersToCocoa(i_key)]; i_key = config_GetInt( p_intf, "key-prev" ); [o_mi_previous setKeyEquivalent: [NSString stringWithFormat:@"%C", VLCKeyToCocoa( i_key )]]; [o_mi_previous setKeyEquivalentModifierMask: VLCModifiersToCocoa(i_key)]; @@ -411,6 +467,18 @@ static VLCMain *_o_sharedMainInstance = nil; i_key = config_GetInt( p_intf, "key-snapshot" ); [o_mi_snapshot setKeyEquivalent: [NSString stringWithFormat:@"%C", VLCKeyToCocoa( i_key )]]; [o_mi_snapshot setKeyEquivalentModifierMask: VLCModifiersToCocoa(i_key)]; + i_key = config_GetInt( p_intf, "key-random" ); + [o_mi_random setKeyEquivalent: [NSString stringWithFormat:@"%C", VLCKeyToCocoa( i_key )]]; + [o_mi_random setKeyEquivalentModifierMask: VLCModifiersToCocoa(i_key)]; + i_key = config_GetInt( p_intf, "key-zoom-half" ); + [o_mi_half_window setKeyEquivalent: [NSString stringWithFormat:@"%C", VLCKeyToCocoa( i_key )]]; + [o_mi_half_window setKeyEquivalentModifierMask: VLCModifiersToCocoa(i_key)]; + i_key = config_GetInt( p_intf, "key-zoom-original" ); + [o_mi_normal_window setKeyEquivalent: [NSString stringWithFormat:@"%C", VLCKeyToCocoa( i_key )]]; + [o_mi_normal_window setKeyEquivalentModifierMask: VLCModifiersToCocoa(i_key)]; + i_key = config_GetInt( p_intf, "key-zoom-double" ); + [o_mi_double_window setKeyEquivalent: [NSString stringWithFormat:@"%C", VLCKeyToCocoa( i_key )]]; + [o_mi_double_window setKeyEquivalentModifierMask: VLCModifiersToCocoa(i_key)]; var_Create( p_intf, "intf-change", VLC_VAR_BOOL ); @@ -446,19 +514,28 @@ static VLCMain *_o_sharedMainInstance = nil; o_size_with_playlist = [o_window contentRectForFrameRect:[o_window frame]].size; - p_playlist = pl_Hold( p_intf ); + p_playlist = pl_Get( p_intf ); - var_Create( p_playlist, "fullscreen", VLC_VAR_BOOL | VLC_VAR_DOINHERIT); val.b_bool = false; var_AddCallback( p_playlist, "fullscreen", FullscreenChanged, self); var_AddCallback( p_intf->p_libvlc, "intf-show", ShowController, self); - pl_Release( p_intf ); - - var_Create( p_intf, "interaction", VLC_VAR_ADDRESS ); - var_AddCallback( p_intf, "interaction", InteractCallback, self ); - interaction_Register( p_intf ); + /* load our Core Dialogs nib */ + nib_coredialogs_loaded = [NSBundle loadNibNamed:@"CoreDialogs" owner: NSApp]; + + /* subscribe to various interactive dialogues */ + var_Create( p_intf, "dialog-error", VLC_VAR_ADDRESS ); + var_AddCallback( p_intf, "dialog-error", DialogCallback, self ); + var_Create( p_intf, "dialog-critical", VLC_VAR_ADDRESS ); + var_AddCallback( p_intf, "dialog-critical", DialogCallback, self ); + var_Create( p_intf, "dialog-login", VLC_VAR_ADDRESS ); + var_AddCallback( p_intf, "dialog-login", DialogCallback, self ); + var_Create( p_intf, "dialog-question", VLC_VAR_ADDRESS ); + var_AddCallback( p_intf, "dialog-question", DialogCallback, self ); + var_Create( p_intf, "dialog-progress-bar", VLC_VAR_ADDRESS ); + var_AddCallback( p_intf, "dialog-progress-bar", DialogCallback, self ); + dialog_Register( p_intf ); /* update the playmode stuff */ p_intf->p_sys->b_playmode_update = true; @@ -468,21 +545,28 @@ static VLCMain *_o_sharedMainInstance = nil; name: NSApplicationDidChangeScreenParametersNotification object: nil]; + /* take care of tint changes during runtime */ o_img_play = [NSImage imageNamed: @"play"]; o_img_pause = [NSImage imageNamed: @"pause"]; - [self controlTintChanged]; - [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector( controlTintChanged ) name: NSControlTintDidChangeNotification object: nil]; - + + /* init Apple Remote support */ + o_remote = [[AppleRemote alloc] init]; + [o_remote setClickCountEnabledButtons: kRemoteButtonPlay]; + [o_remote setDelegate: _o_sharedMainInstance]; + + /* yeah, we are done */ nib_main_loaded = TRUE; } - (void)applicationWillFinishLaunching:(NSNotification *)o_notification { + if( !p_intf ) return; + /* FIXME: don't poll */ interfaceTimer = [[NSTimer scheduledTimerWithTimeInterval: 0.5 target: self selector: @selector(manageIntf:) @@ -499,16 +583,9 @@ static VLCMain *_o_sharedMainInstance = nil; - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { - [self _removeOldPreferences]; - -#ifdef UPDATE_CHECK - /* Check for update silently on startup */ - if( !nib_update_loaded ) - nib_update_loaded = [NSBundle loadNibNamed:@"Update" owner: NSApp]; + if( !p_intf ) return; - if([o_update shouldCheckForUpdate]) - [NSThread detachNewThreadSelector:@selector(checkForUpdate) toTarget:o_update withObject:nil]; -#endif + [self _removeOldPreferences]; /* Handle sleep notification */ [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector:@selector(computerWillSleep:) @@ -519,6 +596,8 @@ static VLCMain *_o_sharedMainInstance = nil; - (void)initStrings { + if( !p_intf ) return; + [o_window setTitle: _NS("VLC media player")]; [self setScrollField:_NS("VLC media player") stopAfter:-1]; @@ -574,11 +653,13 @@ static VLCMain *_o_sharedMainInstance = nil; [o_mi_stop setTitle: _NS("Stop")]; [o_mi_faster setTitle: _NS("Faster")]; [o_mi_slower setTitle: _NS("Slower")]; + [o_mi_normalSpeed setTitle: _NS("Normal rate")]; [o_mi_previous setTitle: _NS("Previous")]; [o_mi_next setTitle: _NS("Next")]; [o_mi_random setTitle: _NS("Random")]; [o_mi_repeat setTitle: _NS("Repeat One")]; [o_mi_loop setTitle: _NS("Repeat All")]; + [o_mi_quitAfterPB setTitle: _NS("Quit after Playback")]; [o_mi_fwd setTitle: _NS("Step Forward")]; [o_mi_bwd setTitle: _NS("Step Backward")]; @@ -636,6 +717,7 @@ static VLCMain *_o_sharedMainInstance = nil; [o_mu_window setTitle: _NS("Window")]; [o_mi_minimize setTitle: _NS("Minimize Window")]; [o_mi_close_window setTitle: _NS("Close Window")]; + [o_mi_player setTitle: _NS("Player...")]; [o_mi_controller setTitle: _NS("Controller...")]; [o_mi_equalizer setTitle: _NS("Equalizer...")]; [o_mi_extended setTitle: _NS("Extended Controls...")]; @@ -687,23 +769,48 @@ static VLCMain *_o_sharedMainInstance = nil; #pragma mark - #pragma mark Termination +- (void)releaseRepresentedObjects:(NSMenu *)the_menu +{ + if( !p_intf ) return; + + NSArray *menuitems_array = [the_menu itemArray]; + for( int i=0; i<[menuitems_array count]; i++ ) + { + NSMenuItem *one_item = [menuitems_array objectAtIndex: i]; + if( [one_item hasSubmenu] ) + [self releaseRepresentedObjects: [one_item submenu]]; + + [one_item setRepresentedObject:NULL]; + } +} + - (void)applicationWillTerminate:(NSNotification *)notification { playlist_t * p_playlist; vout_thread_t * p_vout; int returnedValue = 0; + if( !p_intf ) + return; + + // don't allow a double termination call. If the user has + // already invoked the quit then simply return this time. + int isTerminating = false; + + [o_appLock lock]; + isTerminating = (f_appExit++ > 0 ? 1 : 0); + [o_appLock unlock]; + + if (isTerminating) + return; + msg_Dbg( p_intf, "Terminating" ); - /* Make sure the manage_thread won't call -terminate: again */ - pthread_cancel( manage_thread ); + pthread_join( manage_thread, NULL ); /* Make sure the intf object is getting killed */ vlc_object_kill( p_intf ); - /* Make sure our manage_thread ends */ - pthread_join( manage_thread, NULL ); - /* Make sure the interfaceTimer is destroyed */ [interfaceTimer invalidate]; [interfaceTimer release]; @@ -713,22 +820,24 @@ static VLCMain *_o_sharedMainInstance = nil; config_PutInt( p_intf->p_libvlc, "volume", i_lastShownVolume ); /* save the prefs if they were changed in the extended panel */ - if(o_extended && [o_extended getConfigChanged]) + if(o_extended && [o_extended configChanged]) { [o_extended savePrefs]; } - - interaction_Unregister( p_intf ); - var_DelCallback( p_intf, "interaction", InteractCallback, self ); + + /* unsubscribe from the interactive dialogues */ + dialog_Unregister( p_intf ); + var_DelCallback( p_intf, "dialog-error", DialogCallback, self ); + var_DelCallback( p_intf, "dialog-critical", DialogCallback, self ); + var_DelCallback( p_intf, "dialog-login", DialogCallback, self ); + var_DelCallback( p_intf, "dialog-question", DialogCallback, self ); + var_DelCallback( p_intf, "dialog-progress-bar", DialogCallback, self ); /* remove global observer watching for vout device changes correctly */ [[NSNotificationCenter defaultCenter] removeObserver: self]; - [o_update end]; - /* release some other objects here, because it isn't sure whether dealloc * will be called later on */ - if( nib_about_loaded ) [o_about release]; @@ -762,7 +871,7 @@ static VLCMain *_o_sharedMainInstance = nil; [crashLogURLConnection release]; [o_embedded_list release]; - [o_interaction_list release]; + [o_coredialogs release]; [o_eyetv release]; [o_img_pause_pressed release]; @@ -781,20 +890,29 @@ static VLCMain *_o_sharedMainInstance = nil; /* write cached user defaults to disk */ [[NSUserDefaults standardUserDefaults] synchronize]; + /* Make sure the Menu doesn't have any references to vlc objects anymore */ + [self releaseRepresentedObjects:[NSApp mainMenu]]; + /* Kill the playlist, so that it doesn't accept new request * such as the play request from vlc.c (we are a blocking interface). */ - p_playlist = pl_Hold( p_intf ); + p_playlist = pl_Get( p_intf ); vlc_object_kill( p_playlist ); - pl_Release( p_intf ); - libvlc_Quit( p_intf->p_libvlc ); [self setIntf:nil]; +} + +#pragma mark - +#pragma mark Sparkle delegate +/* received directly before the update gets installed, so let's shut down a bit */ +- (void)updater:(SUUpdater *)updater willInstallUpdate:(SUAppcastItem *)update +{ + [o_remote stopListening: self]; + var_SetInteger( p_intf->p_libvlc, "key-action", ACTIONID_STOP ); - /* Go back to Run() and make libvlc exit properly */ - if( jmpbuffer ) - longjmp( jmpbuffer, 1 ); - /* not reached */ + /* Close the window directly, because we do know that there + * won't be anymore video. It's currently waiting a bit. */ + [[[o_controls voutView] window] orderOut:self]; } #pragma mark - @@ -825,7 +943,6 @@ static NSString * VLCToolbarMediaControl = @"VLCToolbarMediaControl"; { NSToolbarItem *toolbarItem = [[[NSToolbarItem alloc] initWithItemIdentifier: itemIdentifier] autorelease]; - if( [itemIdentifier isEqual: VLCToolbarMediaControl] ) { [toolbarItem setLabel:@"Media Controls"]; @@ -907,10 +1024,13 @@ static NSString * VLCToolbarMediaControl = @"VLCToolbarMediaControl"; application */ - (void)applicationDidBecomeActive:(NSNotification *)aNotification { - [o_remote startListening: self]; + if( !p_intf ) return; + if( config_GetInt( p_intf, "macosx-appleremote" ) == YES ) + [o_remote startListening: self]; } - (void)applicationDidResignActive:(NSNotification *)aNotification { + if( !p_intf ) return; [o_remote stopListening: self]; } @@ -918,11 +1038,9 @@ static NSString * VLCToolbarMediaControl = @"VLCToolbarMediaControl"; - (void)computerWillSleep: (NSNotification *)notification { /* Pause */ - if( p_intf->p_sys->i_play_status == PLAYING_S ) + if( p_intf && p_intf->p_sys->i_play_status == PLAYING_S ) { - vlc_value_t val; - val.i_int = config_GetInt( p_intf, "key-play-pause" ); - var_Set( p_intf->p_libvlc, "key-pressed", val ); + var_SetInteger( p_intf->p_libvlc, "key-action", ACTIONID_PLAY_PAUSE ); } } @@ -1166,8 +1284,6 @@ static struct { NSCarriageReturnCharacter, KEY_ENTER }, { NSEnterCharacter, KEY_ENTER }, { NSBackspaceCharacter, KEY_BACKSPACE }, - { (unichar) ' ', KEY_SPACE }, - { (unichar) 0x1b, KEY_ESC }, {0,0} }; @@ -1223,7 +1339,7 @@ static unsigned int VLCModifiersToCocoa( unsigned int i_key ) unichar key = 0; vlc_value_t val; unsigned int i_pressed_modifiers = 0; - struct hotkey *p_hotkeys; + const struct hotkey *p_hotkeys; int i; val.i_int = 0; @@ -1273,9 +1389,8 @@ static unsigned int VLCModifiersToCocoa( unsigned int i_key ) #pragma mark - #pragma mark Other objects getters -// FIXME: this is ugly and does not respect cocoa naming scheme -- (id)getControls +- (id)controls { if( o_controls ) return o_controls; @@ -1283,7 +1398,7 @@ static unsigned int VLCModifiersToCocoa( unsigned int i_key ) return nil; } -- (id)getSimplePreferences +- (id)simplePreferences { if( !o_sprefs ) return nil; @@ -1294,7 +1409,7 @@ static unsigned int VLCModifiersToCocoa( unsigned int i_key ) return o_sprefs; } -- (id)getPreferences +- (id)preferences { if( !o_prefs ) return nil; @@ -1305,7 +1420,7 @@ static unsigned int VLCModifiersToCocoa( unsigned int i_key ) return o_prefs; } -- (id)getPlaylist +- (id)playlist { if( o_playlist ) return o_playlist; @@ -1318,7 +1433,7 @@ static unsigned int VLCModifiersToCocoa( unsigned int i_key ) return ![o_btn_playlist state]; } -- (id)getInfo +- (id)info { if( o_info ) return o_info; @@ -1326,7 +1441,7 @@ static unsigned int VLCModifiersToCocoa( unsigned int i_key ) return nil; } -- (id)getWizard +- (id)wizard { if( o_wizard ) return o_wizard; @@ -1334,12 +1449,14 @@ static unsigned int VLCModifiersToCocoa( unsigned int i_key ) return nil; } -- (id)getVLM +#ifdef ENABLE_VLM +- (id)vlm { return o_vlm; } +#endif -- (id)getBookmarks +- (id)bookmarks { if( o_bookmarks ) return o_bookmarks; @@ -1347,7 +1464,7 @@ static unsigned int VLCModifiersToCocoa( unsigned int i_key ) return nil; } -- (id)getEmbeddedList +- (id)embeddedList { if( o_embedded_list ) return o_embedded_list; @@ -1355,15 +1472,15 @@ static unsigned int VLCModifiersToCocoa( unsigned int i_key ) return nil; } -- (id)getInteractionList +- (id)coreDialogProvider { - if( o_interaction_list ) - return o_interaction_list; + if( o_coredialogs ) + return o_coredialogs; return nil; } -- (id)getMainIntfPgbar +- (id)mainIntfPgbar { if( o_main_pgbar ) return o_main_pgbar; @@ -1371,19 +1488,19 @@ static unsigned int VLCModifiersToCocoa( unsigned int i_key ) return nil; } -- (id)getControllerWindow +- (id)controllerWindow { if( o_window ) return o_window; return nil; } -- (id)getVoutMenu +- (id)voutMenu { return o_vout_menu; } -- (id)getEyeTVController +- (id)eyeTVController { if( o_eyetv ) return o_eyetv; @@ -1391,6 +1508,11 @@ static unsigned int VLCModifiersToCocoa( unsigned int i_key ) return nil; } +- (id)appleRemoteController +{ + return o_remote; +} + #pragma mark - #pragma mark Polling @@ -1413,7 +1535,7 @@ struct manage_cleanup_stack { id self; }; -static void * manage_cleanup( void * args ) +static void manage_cleanup( void * args ) { struct manage_cleanup_stack * manage_cleanup_stack = args; intf_thread_t * p_intf = manage_cleanup_stack->p_intf; @@ -1421,16 +1543,13 @@ static void * manage_cleanup( void * args ) id self = manage_cleanup_stack->self; playlist_t * p_playlist = manage_cleanup_stack->p_playlist; - var_AddCallback( p_playlist, "item-current", PlaylistChanged, self ); - var_AddCallback( p_playlist, "intf-change", PlaylistChanged, self ); - var_AddCallback( p_playlist, "item-change", PlaylistChanged, self ); - var_AddCallback( p_playlist, "playlist-item-append", PlaylistChanged, self ); - var_AddCallback( p_playlist, "playlist-item-deleted", PlaylistChanged, self ); - - pl_Release( p_intf ); + var_DelCallback( p_playlist, "item-current", PlaylistChanged, self ); + var_DelCallback( p_playlist, "intf-change", PlaylistChanged, self ); + var_DelCallback( p_playlist, "item-change", PlaylistChanged, self ); + var_DelCallback( p_playlist, "playlist-item-append", PlaylistChanged, self ); + var_DelCallback( p_playlist, "playlist-item-deleted", PlaylistChanged, self ); if( p_input ) vlc_object_release( p_input ); - return NULL; } - (void)manage @@ -1442,7 +1561,7 @@ static void * manage_cleanup( void * args ) vlc_thread_set_priority( p_intf, VLC_THREAD_PRIORITY_LOW ); - p_playlist = pl_Hold( p_intf ); + p_playlist = pl_Get( p_intf ); var_AddCallback( p_playlist, "item-current", PlaylistChanged, self ); var_AddCallback( p_playlist, "intf-change", PlaylistChanged, self ); @@ -1453,10 +1572,10 @@ static void * manage_cleanup( void * args ) struct manage_cleanup_stack stack = { p_intf, &p_input, p_playlist, self }; pthread_cleanup_push(manage_cleanup, &stack); - while( true ) + bool exitLoop = false; + while( !exitLoop ) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; - vlc_mutex_lock( &p_intf->change_lock ); if( !p_input ) { @@ -1486,25 +1605,26 @@ static void * manage_cleanup( void * args ) /* Manage volume status */ [self manageVolumeSlider]; - vlc_mutex_unlock( &p_intf->change_lock ); - msleep( INTF_IDLE_SLEEP ); [pool release]; + + [o_appLock lock]; + exitLoop = (f_appExit != 0 ? true : false); + [o_appLock unlock]; } pthread_cleanup_pop(1); - msg_Dbg( p_intf, "Killing the Mac OS X module" ); - - /* We are dead, terminate */ - [NSApp performSelectorOnMainThread: @selector(terminate:) withObject:nil waitUntilDone:NO]; + msg_Dbg( p_intf, "OS X Manage thread terminating" ); } - (void)manageVolumeSlider { audio_volume_t i_volume; - aout_VolumeGet( p_intf, &i_volume ); + playlist_t * p_playlist = pl_Get( p_intf ); + + aout_VolumeGet( p_playlist, &i_volume ); if( i_volume != i_lastShownVolume ) { @@ -1526,6 +1646,18 @@ static void * manage_cleanup( void * args ) p_intf->p_sys->b_intf_update = true; p_intf->p_sys->b_input_update = false; [self setupMenus]; /* Make sure input menu is up to date */ + + /* update our info-panel to reflect the new item, if we don't show + * the playlist or the selection is empty */ + if( [self isPlaylistCollapsed] == YES ) + { + playlist_t * p_playlist = pl_Get( p_intf ); + PL_LOCK; + playlist_item_t * p_item = playlist_CurrentPlayingItem( p_playlist ); + PL_UNLOCK; + if( p_item ) + [[self info] updatePanelWithItem: p_item->p_input]; + } } if( p_intf->p_sys->b_intf_update ) { @@ -1535,11 +1667,14 @@ static void * manage_cleanup( void * args ) bool b_seekable = false; bool b_chapters = false; - playlist_t * p_playlist = pl_Hold( p_intf ); - /* TODO: fix i_size use */ - b_plmul = p_playlist->items.i_size > 1; + playlist_t * p_playlist = pl_Get( p_intf ); + + PL_LOCK; + b_plmul = playlist_CurrentSize( p_playlist ) > 1; + PL_UNLOCK; p_input = playlist_CurrentInput( p_playlist ); + bool b_buffering = NO; if( ( b_input = ( p_input != NULL ) ) ) @@ -1552,15 +1687,6 @@ static void * manage_cleanup( void * args ) b_buffering = YES; } - /* update our info-panel to reflect the new item, if we don't show - * the playlist or the selection is empty */ - if( [self isPlaylistCollapsed] == YES ) - { - PL_LOCK; - [[self getInfo] updatePanelWithItem: playlist_CurrentPlayingItem( p_playlist )->p_input]; - PL_UNLOCK; - } - /* seekable streams */ b_seekable = var_GetBool( p_input, "can-seek" ); @@ -1571,7 +1697,6 @@ static void * manage_cleanup( void * args ) //b_chapters = p_input->stream.i_area_nb > 1; vlc_object_release( p_input ); } - pl_Release( p_intf ); if( b_buffering ) { @@ -1586,18 +1711,22 @@ static void * manage_cleanup( void * args ) } [o_btn_stop setEnabled: b_input]; + [o_embedded_window setStop: b_input]; [o_btn_ff setEnabled: b_seekable]; [o_btn_rewind setEnabled: b_seekable]; [o_btn_prev setEnabled: (b_plmul || b_chapters)]; + [o_embedded_window setPrev: (b_plmul || b_chapters)]; [o_btn_next setEnabled: (b_plmul || b_chapters)]; + [o_embedded_window setNext: (b_plmul || b_chapters)]; [o_timeslider setFloatValue: 0.0]; [o_timeslider setEnabled: b_seekable]; [o_timefield setStringValue: @"00:00"]; - [[[self getControls] getFSPanel] setStreamPos: 0 andTime: @"00:00"]; - [[[self getControls] getFSPanel] setSeekable: b_seekable]; + [[[self controls] fspanel] setStreamPos: 0 andTime: @"00:00"]; + [[[self controls] fspanel] setSeekable: b_seekable]; [o_embedded_window setSeekable: b_seekable]; + [o_embedded_window setTime:@"00:00" position:0.0]; p_intf->p_sys->b_current_title_update = true; @@ -1623,7 +1752,7 @@ static void * manage_cleanup( void * args ) if( p_intf->p_sys->b_intf_show ) { if( [[o_controls voutView] isFullscreen] && config_GetInt( VLCIntf, "macosx-fspanel" ) ) - [[o_controls getFSPanel] fadeIn]; + [[o_controls fspanel] fadeIn]; else [o_window makeKeyAndOrderFront: self]; @@ -1649,11 +1778,12 @@ static void * manage_cleanup( void * args ) free(name); [self setScrollField: aString stopAfter:-1]; - [[[self getControls] getFSPanel] setStreamTitle: aString]; + [[[self controls] fspanel] setStreamTitle: aString]; [[o_controls voutView] updateTitle]; [o_playlist updateRowSelection]; + p_intf->p_sys->b_current_title_update = FALSE; } @@ -1672,10 +1802,16 @@ static void * manage_cleanup( void * args ) var_Get( p_input, "time", &time ); - o_time = [NSString stringWithUTF8String: secstotimestr( psz_time, (time.i_time / 1000000) )]; + mtime_t dur = input_item_GetDuration( input_GetItem( p_input ) ); + if( b_time_remaining && dur != -1 ) + { + o_time = [NSString stringWithFormat: @"-%s", secstotimestr( psz_time, ((dur - time.i_time) / 1000000))]; + } + else + o_time = [NSString stringWithUTF8String: secstotimestr( psz_time, (time.i_time / 1000000) )]; [o_timefield setStringValue: o_time]; - [[[self getControls] getFSPanel] setStreamPos: f_updated andTime: o_time]; + [[[self controls] fspanel] setStreamPos: f_updated andTime: o_time]; [o_embedded_window setTime: o_time position: f_updated]; } @@ -1711,7 +1847,9 @@ static void * manage_cleanup( void * args ) i_volume_step = config_GetInt( p_intf->p_libvlc, "volume-step" ); [o_volumeslider setFloatValue: (float)i_lastShownVolume / i_volume_step]; [o_volumeslider setEnabled: TRUE]; - [[[self getControls] getFSPanel] setVolumeLevel: (float)i_lastShownVolume / i_volume_step]; + [o_embedded_window setVolumeSlider: (float)i_lastShownVolume / i_volume_step]; + [o_embedded_window setVolumeEnabled: TRUE]; + [[[self controls] fspanel] setVolumeLevel: (float)i_lastShownVolume / i_volume_step]; p_intf->p_sys->b_mute = ( i_lastShownVolume == 0 ); p_intf->p_sys->b_volume_update = FALSE; } @@ -1734,7 +1872,7 @@ end: - (void)setupMenus { - playlist_t * p_playlist = pl_Hold( p_intf ); + playlist_t * p_playlist = pl_Get( p_intf ); input_thread_t * p_input = playlist_CurrentInput( p_playlist ); if( p_input != NULL ) { @@ -1760,8 +1898,7 @@ end: if( [o_mi_videotrack isEnabled] == YES ) [o_mi_subtitle setEnabled: YES]; - aout_instance_t * p_aout = vlc_object_find( p_intf, VLC_OBJECT_AOUT, - FIND_ANYWHERE ); + aout_instance_t * p_aout = input_GetAout( p_input ); if( p_aout != NULL ) { [o_controls setupVarMenuItem: o_mi_channels target: (vlc_object_t *)p_aout @@ -1775,8 +1912,7 @@ end: vlc_object_release( (vlc_object_t *)p_aout ); } - vout_thread_t * p_vout = vlc_object_find( p_intf, VLC_OBJECT_VOUT, - FIND_ANYWHERE ); + vout_thread_t * p_vout = input_GetVout( p_input ); if( p_vout != NULL ) { @@ -1792,34 +1928,25 @@ end: var: "video-device" selector: @selector(toggleVar:)]; [o_controls setupVarMenuItem: o_mi_deinterlace target: (vlc_object_t *)p_vout - var: "deinterlace" selector: @selector(toggleVar:)]; + var: "deinterlace-mode" selector: @selector(toggleVar:)]; - p_dec_obj = (vlc_object_t *)vlc_object_find( - (vlc_object_t *)p_vout, - VLC_OBJECT_DECODER, - FIND_PARENT ); - if( p_dec_obj != NULL ) - { - [o_controls setupVarMenuItem: o_mi_ffmpeg_pp target: - (vlc_object_t *)p_dec_obj var:"ffmpeg-pp-q" selector: +#if 1 + [o_controls setupVarMenuItem: o_mi_ffmpeg_pp target: + (vlc_object_t *)p_vout var:"postprocess" selector: @selector(toggleVar:)]; - vlc_object_release(p_dec_obj); - } +#endif vlc_object_release( (vlc_object_t *)p_vout ); } vlc_object_release( p_input ); } - pl_Release( p_intf ); } - (void)refreshVoutDeviceMenu:(NSNotification *)o_notification { - int x,y = 0; - vout_thread_t * p_vout = vlc_object_find( p_intf, VLC_OBJECT_VOUT, - FIND_ANYWHERE ); - - if(! p_vout ) + int x, y = 0; + vout_thread_t * p_vout = getVout(); + if( !p_vout ) return; /* clean the menu before adding new entries */ @@ -1847,11 +1974,12 @@ end: else i_end_scroll = -1; [o_scrollfield setStringValue: o_string]; + [o_embedded_window setScrollString: o_string]; } - (void)resetScrollField { - playlist_t * p_playlist = pl_Hold( p_intf ); + playlist_t * p_playlist = pl_Get( p_intf ); input_thread_t * p_input = playlist_CurrentInput( p_playlist ); i_end_scroll = -1; @@ -1866,12 +1994,10 @@ end: o_temp = [NSString stringWithUTF8String:p_item->p_input->psz_name]; PL_UNLOCK; [self setScrollField: o_temp stopAfter:-1]; - [[[self getControls] getFSPanel] setStreamTitle: o_temp]; + [[[self controls] fspanel] setStreamTitle: o_temp]; vlc_object_release( p_input ); - pl_Release( p_intf ); return; } - pl_Release( p_intf ); [self setScrollField: _NS("VLC media player") stopAfter:-1]; } @@ -1879,7 +2005,7 @@ end: { if( i_status == PLAYING_S ) { - [[[self getControls] getFSPanel] setPause]; + [[[self controls] fspanel] setPause]; [o_btn_play setImage: o_img_pause]; [o_btn_play setAlternateImage: o_img_pause_pressed]; [o_btn_play setToolTip: _NS("Pause")]; @@ -1889,7 +2015,7 @@ end: } else { - [[[self getControls] getFSPanel] setPlay]; + [[[self controls] fspanel] setPlay]; [o_btn_play setImage: o_img_play]; [o_btn_play setAlternateImage: o_img_play_pressed]; [o_btn_play setToolTip: _NS("Play")]; @@ -1935,7 +2061,7 @@ end: default: return; } - p_playlist = pl_Hold( p_intf ); + p_playlist = pl_Get( p_intf ); p_input = playlist_CurrentInput( p_playlist ); if( p_input != NULL ) { @@ -1950,15 +2076,27 @@ end: var_Get( p_input, "time", &time ); - o_time = [NSString stringWithUTF8String: secstotimestr( psz_time, (time.i_time / 1000000) )]; + mtime_t dur = input_item_GetDuration( input_GetItem( p_input ) ); + if( b_time_remaining && dur != -1 ) + { + o_time = [NSString stringWithFormat: @"-%s", secstotimestr( psz_time, ((dur - time.i_time) / 1000000) )]; + } + else + o_time = [NSString stringWithUTF8String: secstotimestr( psz_time, (time.i_time / 1000000) )]; + [o_timefield setStringValue: o_time]; - [[[self getControls] getFSPanel] setStreamPos: f_updated andTime: o_time]; + [[[self controls] fspanel] setStreamPos: f_updated andTime: o_time]; [o_embedded_window setTime: o_time position: f_updated]; vlc_object_release( p_input ); } - pl_Release( p_intf ); } +- (IBAction)timeFieldWasClicked:(id)sender +{ + b_time_remaining = !b_time_remaining; +} + + #pragma mark - #pragma mark Recent Items @@ -2052,10 +2190,16 @@ end: - (IBAction)showVLM:(id)sender { +#ifdef ENABLE_VLM if( !nib_vlm_loaded ) nib_vlm_loaded = [NSBundle loadNibNamed:@"VLM" owner: NSApp]; [o_vlm showVLMWindow]; +#else + NSAlert *theAlert; + theAlert = [NSAlert alertWithMessageText:_NS("VLM not available") defaultButton:_NS("OK") alternateButton:nil otherButton:nil informativeTextWithFormat:_NS("The VideoLAN Manager was not enabled in this version of VLC.")]; + [theAlert runModal]; +#endif } - (IBAction)showExtended:(id)sender @@ -2096,21 +2240,6 @@ end: [o_sprefs showSimplePrefs]; } -#pragma mark - -#pragma mark Update - -- (IBAction)checkForUpdate:(id)sender -{ -#ifdef UPDATE_CHECK - if( !nib_update_loaded ) - nib_update_loaded = [NSBundle loadNibNamed:@"Update" owner: NSApp]; - [o_update showUpdateWindow]; -#else - msg_Err( VLCIntf, "Update checker wasn't enabled in this build" ); - intf_UserFatal( VLCIntf, false, _("Update check failed"), _("Checking for updates was not enabled in this build.") ); -#endif -} - #pragma mark - #pragma mark Help and Docs @@ -2214,9 +2343,6 @@ end: - (void)connectionDidFinishLoading:(NSURLConnection *)connection { - NSRunInformationalAlertPanel(_NS("Crash Report successfully sent"), - _NS("Thanks for your report!"), - _NS("OK"), nil, nil, nil); [crashLogURLConnection release]; crashLogURLConnection = nil; } @@ -2378,7 +2504,7 @@ end: - (IBAction)viewErrorsAndWarnings:(id)sender { - [[[self getInteractionList] getErrorPanel] showPanel]; + [[[self coreDialogProvider] errorPanel] showPanel]; } - (IBAction)showMessagesPanel:(id)sender @@ -2442,11 +2568,10 @@ end: [o_msg_lock lock]; - if( [o_msg_arr count] + 2 > 400 ) + if( [o_msg_arr count] + 2 > 600 ) { - unsigned rid[] = { 0, 1 }; - [o_msg_arr removeObjectsFromIndices: (unsigned *)&rid - numIndices: sizeof(rid)/sizeof(rid[0])]; + [o_msg_arr removeObjectAtIndex: 0]; + [o_msg_arr removeObjectAtIndex: 1]; } o_attr = [NSDictionary dictionaryWithObject: o_gray @@ -2573,7 +2698,7 @@ end: else [o_btn_playlist setState: YES]; - [[self getPlaylist] outlineViewSelectionDidChange: NULL]; + [[self playlist] outlineViewSelectionDidChange: NULL]; } - (NSSize)windowWillResize:(NSWindow *)sender toSize:(NSSize)proposedFrameSize @@ -2714,3 +2839,99 @@ end: } @end + +/***************************************************************************** + * VLCApplication interface + * exclusively used to implement media key support on Al Apple keyboards + * b_justJumped is required as the keyboard send its events faster than + * the user can actually jump through his media + *****************************************************************************/ + +@implementation VLCApplication + +- (void)awakeFromNib +{ + b_active = b_mediaKeySupport = config_GetInt( VLCIntf, "macosx-mediakeys" ); + b_activeInBackground = config_GetInt( VLCIntf, "macosx-mediakeys-background" ); + [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(coreChangedMediaKeySupportSetting:) name: @"VLCMediaKeySupportSettingChanged" object: nil]; + [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(appGotActiveOrInactive:) name: @"NSApplicationDidBecomeActiveNotification" object: nil]; + [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(appGotActiveOrInactive:) name: @"NSApplicationWillResignActiveNotification" object: nil]; +} + +- (void)dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver: self]; + [super dealloc]; +} + +- (void)appGotActiveOrInactive: (NSNotification *)o_notification +{ + if(( [[o_notification name] isEqualToString: @"NSApplicationWillResignActiveNotification"] && !b_activeInBackground ) || !b_mediaKeySupport) + b_active = NO; + else + b_active = YES; +} + +- (void)coreChangedMediaKeySupportSetting: (NSNotification *)o_notification +{ + b_active = b_mediaKeySupport = config_GetInt( VLCIntf, "macosx-mediakeys" ); + b_activeInBackground = config_GetInt( VLCIntf, "macosx-mediakeys-background" ); +} + + +- (void)sendEvent: (NSEvent*)event +{ + if( b_active ) + { + if( [event type] == NSSystemDefined && [event subtype] == 8 ) + { + int keyCode = (([event data1] & 0xFFFF0000) >> 16); + int keyFlags = ([event data1] & 0x0000FFFF); + int keyState = (((keyFlags & 0xFF00) >> 8)) == 0xA; + int keyRepeat = (keyFlags & 0x1); + + if( keyCode == NX_KEYTYPE_PLAY && keyState == 0 ) + var_SetInteger( VLCIntf->p_libvlc, "key-action", ACTIONID_PLAY_PAUSE ); + + if( keyCode == NX_KEYTYPE_FAST && !b_justJumped ) + { + if( keyState == 0 && keyRepeat == 0 ) + { + var_SetInteger( VLCIntf->p_libvlc, "key-action", ACTIONID_NEXT ); + } + else if( keyRepeat == 1 ) + { + var_SetInteger( VLCIntf->p_libvlc, "key-action", ACTIONID_JUMP_FORWARD_SHORT ); + b_justJumped = YES; + [self performSelector:@selector(resetJump) + withObject: NULL + afterDelay:0.25]; + } + } + + if( keyCode == NX_KEYTYPE_REWIND && !b_justJumped ) + { + if( keyState == 0 && keyRepeat == 0 ) + { + var_SetInteger( VLCIntf->p_libvlc, "key-action", ACTIONID_PREV ); + } + else if( keyRepeat == 1 ) + { + var_SetInteger( VLCIntf->p_libvlc, "key-action", ACTIONID_JUMP_BACKWARD_SHORT ); + b_justJumped = YES; + [self performSelector:@selector(resetJump) + withObject: NULL + afterDelay:0.25]; + } + } + } + } + [super sendEvent: event]; +} + +- (void)resetJump +{ + b_justJumped = NO; +} + +@end