intf.m 82.4 KB
Newer Older
1
/*****************************************************************************
2
 * intf.m: MacOS X interface module
3
 *****************************************************************************
4
 * Copyright (C) 2002-2008 the VideoLAN team
5
 * $Id$
6 7 8
 *
 * Authors: Jon Lech Johansen <jon-vl@nanocrew.net>
 *          Christophe Massiot <massiot@via.ecp.fr>
9
 *          Derk-Jan Hartman <hartman at videolan.org>
10
 *          Felix Paul Kühne <fkuehne at videolan dot org>
11 12 13 14 15
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
16
 *
17 18 19 20 21 22 23
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
Antoine Cellerier's avatar
Antoine Cellerier committed
24
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
25 26 27 28 29 30 31 32
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/
#include <stdlib.h>                                      /* malloc(), free() */
#include <sys/param.h>                                    /* for MAXPATHLEN */
#include <string.h>
33
#include <vlc_keys.h>
34

Rafaël Carré's avatar
Rafaël Carré committed
35 36 37 38
#ifdef HAVE_CONFIG_H
#   include "config.h"
#endif

39 40 41 42 43
#import "intf.h"
#import "fspanel.h"
#import "vout.h"
#import "prefs.h"
#import "playlist.h"
44
#import "playlistinfo.h"
45 46 47 48 49 50 51 52 53 54
#import "controls.h"
#import "about.h"
#import "open.h"
#import "wizard.h"
#import "extended.h"
#import "bookmarks.h"
#import "interaction.h"
#import "embeddedwindow.h"
#import "update.h"
#import "AppleRemote.h"
55
#import "eyetv.h"
56
#import "simple_prefs.h"
57

58
#import <vlc_input.h>
59
#import <vlc_interface.h>
60
#import <AddressBook/AddressBook.h>
61

62 63 64
/*****************************************************************************
 * Local prototypes.
 *****************************************************************************/
65
static void Run ( intf_thread_t *p_intf );
66

67
static void * ManageThread( void *user_data );
68

69 70
static unichar VLCKeyToCocoa( unsigned int i_key );
static unsigned int VLCModifiersToCocoa( unsigned int i_key );
71

72
#pragma mark -
73
#pragma mark VLC Interface Object Callbacks
74

75 76 77
/*****************************************************************************
 * OpenIntf: initialize interface
 *****************************************************************************/
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
78
int OpenIntf ( vlc_object_t *p_this )
Jérome Decoodt's avatar
Jérome Decoodt committed
79
{
80 81 82 83 84 85 86 87 88
    intf_thread_t *p_intf = (intf_thread_t*) p_this;

    p_intf->p_sys = malloc( sizeof( intf_sys_t ) );
    if( p_intf->p_sys == NULL )
    {
        return( 1 );
    }

    memset( p_intf->p_sys, 0, sizeof( *p_intf->p_sys ) );
Jérome Decoodt's avatar
Jérome Decoodt committed
89

90
    p_intf->p_sys->o_pool = [[NSAutoreleasePool alloc] init];
91

92
    p_intf->p_sys->p_sub = msg_Subscribe( p_intf );
93
    p_intf->pf_run = Run;
94
    p_intf->b_should_run_on_first_thread = true;
95 96 97 98 99 100 101

    return( 0 );
}

/*****************************************************************************
 * CloseIntf: destroy interface
 *****************************************************************************/
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
102
void CloseIntf ( vlc_object_t *p_this )
103 104
{
    intf_thread_t *p_intf = (intf_thread_t*) p_this;
Jérome Decoodt's avatar
Jérome Decoodt committed
105

106
    msg_Unsubscribe( p_intf, p_intf->p_sys->p_sub );
Jérome Decoodt's avatar
Jérome Decoodt committed
107

108
    [p_intf->p_sys->o_pool release];
Jérome Decoodt's avatar
Jérome Decoodt committed
109

110 111 112 113 114 115
    free( p_intf->p_sys );
}

/*****************************************************************************
 * Run: main loop
 *****************************************************************************/
116 117
jmp_buf jmpbuffer;

118 119
static void Run( intf_thread_t *p_intf )
{
120 121
    sigset_t set;

122 123 124 125
    /* Do it again - for some unknown reason, vlc_thread_create() often
     * fails to go to real-time priority with the first launched thread
     * (???) --Meuuh */
    vlc_thread_set_priority( p_intf, VLC_THREAD_PRIORITY_LOW );
126 127 128 129 130 131 132 133 134

    /* Make sure the "force quit" menu item does quit instantly.
     * VLC overrides SIGTERM which is sent by the "force quit"
     * menu item to make sure deamon mode quits gracefully, so
     * we un-override SIGTERM here. */
    sigemptyset( &set );
    sigaddset( &set, SIGTERM );
    pthread_sigmask( SIG_UNBLOCK, &set, NULL );

135 136 137 138
    NSAutoreleasePool * o_pool = [[NSAutoreleasePool alloc] init];

    /* Install a jmpbuffer to where we can go back before the NSApp exit
     * see applicationWillTerminate: */
139
    [NSApplication sharedApplication];
140

Derk-Jan Hartman's avatar
-  
Derk-Jan Hartman committed
141
    [[VLCMain sharedInstance] setIntf: p_intf];
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
142
    [NSBundle loadNibNamed: @"MainMenu" owner: NSApp];
143 144 145 146 147

    /* Install a jmpbuffer to where we can go back before the NSApp exit
     * see applicationWillTerminate: */
    if(setjmp(jmpbuffer) == 0)
        [NSApp run];
148 149

    [o_pool release];
150 151
}

152 153
#pragma mark -
#pragma mark Variables Callback
154

155 156 157 158
/*****************************************************************************
 * playlistChanged: Callback triggered by the intf-change playlist
 * variable, to let the intf update the playlist.
 *****************************************************************************/
159
static int PlaylistChanged( vlc_object_t *p_this, const char *psz_variable,
160 161
                     vlc_value_t old_val, vlc_value_t new_val, void *param )
{
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
162
    intf_thread_t * p_intf = VLCIntf;
163
    p_intf->p_sys->b_intf_update = true;
164
    p_intf->p_sys->b_playlist_update = true;
165 166
    p_intf->p_sys->b_playmode_update = true;
    p_intf->p_sys->b_current_title_update = true;
167 168 169 170 171 172 173 174 175 176 177 178
    return VLC_SUCCESS;
}

/*****************************************************************************
 * ShowController: Callback triggered by the show-intf playlist variable
 * through the ShowIntf-control-intf, to let us show the controller-win;
 * usually when in fullscreen-mode
 *****************************************************************************/
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;
179
    p_intf->p_sys->b_intf_show = true;
180 181 182
    return VLC_SUCCESS;
}

183 184 185 186
/*****************************************************************************
 * FullscreenChanged: Callback triggered by the fullscreen-change playlist
 * variable, to let the intf update the controller.
 *****************************************************************************/
187
static int FullscreenChanged( vlc_object_t *p_this, const char *psz_variable,
188 189 190
                     vlc_value_t old_val, vlc_value_t new_val, void *param )
{
    intf_thread_t * p_intf = VLCIntf;
191
    p_intf->p_sys->b_fullscreen_update = true;
192 193 194
    return VLC_SUCCESS;
}

195 196 197 198 199 200 201 202 203 204 205
/*****************************************************************************
 * InteractCallback: Callback triggered by the interaction
 * variable, 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 )
{
    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];
206
 
207 208
    [[NSNotificationCenter defaultCenter] postNotificationName: @"VLCNewInteractionEventNotification" object:[interface getInteractionList]
     userInfo:[NSDictionary dictionaryWithObject:o_value forKey:@"VLCDialogPointer"]];
209
 
210 211 212
    [o_pool release];
    return VLC_SUCCESS;
}
213

214
#pragma mark -
215

216
/*****************************************************************************
Jérome Decoodt's avatar
Jérome Decoodt committed
217
 * VLCMain implementation
218 219 220
 *****************************************************************************/
@implementation VLCMain

221 222 223
#pragma mark -
#pragma mark Initialization

Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
224 225 226 227 228 229 230
static VLCMain *_o_sharedMainInstance = nil;

+ (VLCMain *)sharedInstance
{
    return _o_sharedMainInstance ? _o_sharedMainInstance : [[self alloc] init];
}

Jérome Decoodt's avatar
Jérome Decoodt committed
231
- (id)init
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
232
{
233 234
    if( _o_sharedMainInstance) 
    {
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
235
        [self dealloc];
236 237 238
        return _o_sharedMainInstance;
    } 
    else
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
239
        _o_sharedMainInstance = [super init];
240

241
    o_about = [[VLAboutBox alloc] init];
242
    o_prefs = nil;
243
    o_open = [[VLCOpen alloc] init];
244
    o_wizard = [[VLCWizard alloc] init];
245
    o_extended = nil;
246
    o_bookmarks = [[VLCBookmarks alloc] init];
247
    o_embedded_list = [[VLCEmbeddedList alloc] init];
248
    o_interaction_list = [[VLCInteractionList alloc] init];
249
    o_info = [[VLCInfo alloc] init];
250
#ifdef UPDATE_CHECK
Rafaël Carré's avatar
Rafaël Carré committed
251
    o_update = [[VLCUpdate alloc] init];
252
#endif
253 254

    i_lastShownVolume = -1;
255 256

    o_remote = [[AppleRemote alloc] init];
257
    [o_remote setClickCountEnabledButtons: kRemoteButtonPlay];
258
    [o_remote setDelegate: _o_sharedMainInstance];
259

260 261 262 263 264 265 266 267
    o_eyetv = [[VLCEyeTVController alloc] init];

    /* announce our launch to a potential eyetv plugin */
    [[NSDistributedNotificationCenter defaultCenter] postNotificationName: @"VLCOSXGUIInit"
                                                                   object: @"VLCEyeTVSupport"
                                                                 userInfo: NULL
                                                       deliverImmediately: YES];

Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
268 269 270 271 272 273 274 275 276 277 278
    return _o_sharedMainInstance;
}

- (void)setIntf: (intf_thread_t *)p_mainintf {
    p_intf = p_mainintf;
}

- (intf_thread_t *)getIntf {
    return p_intf;
}

279 280
- (void)awakeFromNib
{
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
281
    unsigned int i_key = 0;
282
    playlist_t *p_playlist;
283
    vlc_value_t val;
284

285 286 287
    /* Check if we already did this once. Opening the other nibs calls it too, because VLCMain is the owner */
    if( nib_main_loaded ) return;

288
    [self initStrings];
289 290 291

    [o_window setExcludedFromWindowsMenu: YES];
    [o_msgs_panel setExcludedFromWindowsMenu: YES];
292
    [o_msgs_panel setDelegate: self];
Jérome Decoodt's avatar
Jérome Decoodt committed
293

294 295 296 297 298 299 300 301 302
    /* In code and not in Nib for 10.4 compat */
    NSToolbar * toolbar = [[[NSToolbar alloc] initWithIdentifier:@"mainControllerToolbar"] autorelease];
    [toolbar setDelegate:self];
    [toolbar setShowsBaselineSeparator:NO];
    [toolbar setAllowsUserCustomization:NO];
    [toolbar setDisplayMode:NSToolbarDisplayModeIconOnly];
    [toolbar setAutosavesConfiguration:YES];
    [o_window setToolbar:toolbar];

303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323
    i_key = config_GetInt( p_intf, "key-quit" );
    [o_mi_quit setKeyEquivalent: [NSString stringWithFormat:@"%C", VLCKeyToCocoa( i_key )]];
    [o_mi_quit setKeyEquivalentModifierMask: VLCModifiersToCocoa(i_key)];
    i_key = config_GetInt( p_intf, "key-play-pause" );
    [o_mi_play setKeyEquivalent: [NSString stringWithFormat:@"%C", VLCKeyToCocoa( i_key )]];
    [o_mi_play setKeyEquivalentModifierMask: VLCModifiersToCocoa(i_key)];
    i_key = config_GetInt( p_intf, "key-stop" );
    [o_mi_stop setKeyEquivalent: [NSString stringWithFormat:@"%C", VLCKeyToCocoa( i_key )]];
    [o_mi_stop setKeyEquivalentModifierMask: VLCModifiersToCocoa(i_key)];
    i_key = config_GetInt( p_intf, "key-faster" );
    [o_mi_faster setKeyEquivalent: [NSString stringWithFormat:@"%C", VLCKeyToCocoa( i_key )]];
    [o_mi_faster setKeyEquivalentModifierMask: VLCModifiersToCocoa(i_key)];
    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-prev" );
    [o_mi_previous setKeyEquivalent: [NSString stringWithFormat:@"%C", VLCKeyToCocoa( i_key )]];
    [o_mi_previous setKeyEquivalentModifierMask: VLCModifiersToCocoa(i_key)];
    i_key = config_GetInt( p_intf, "key-next" );
    [o_mi_next setKeyEquivalent: [NSString stringWithFormat:@"%C", VLCKeyToCocoa( i_key )]];
    [o_mi_next setKeyEquivalentModifierMask: VLCModifiersToCocoa(i_key)];
324
    i_key = config_GetInt( p_intf, "key-jump+short" );
325 326
    [o_mi_fwd setKeyEquivalent: [NSString stringWithFormat:@"%C", VLCKeyToCocoa( i_key )]];
    [o_mi_fwd setKeyEquivalentModifierMask: VLCModifiersToCocoa(i_key)];
327
    i_key = config_GetInt( p_intf, "key-jump-short" );
328 329
    [o_mi_bwd setKeyEquivalent: [NSString stringWithFormat:@"%C", VLCKeyToCocoa( i_key )]];
    [o_mi_bwd setKeyEquivalentModifierMask: VLCModifiersToCocoa(i_key)];
330
    i_key = config_GetInt( p_intf, "key-jump+medium" );
331 332
    [o_mi_fwd1m setKeyEquivalent: [NSString stringWithFormat:@"%C", VLCKeyToCocoa( i_key )]];
    [o_mi_fwd1m setKeyEquivalentModifierMask: VLCModifiersToCocoa(i_key)];
333
    i_key = config_GetInt( p_intf, "key-jump-medium" );
334 335
    [o_mi_bwd1m setKeyEquivalent: [NSString stringWithFormat:@"%C", VLCKeyToCocoa( i_key )]];
    [o_mi_bwd1m setKeyEquivalentModifierMask: VLCModifiersToCocoa(i_key)];
336
    i_key = config_GetInt( p_intf, "key-jump+long" );
337 338
    [o_mi_fwd5m setKeyEquivalent: [NSString stringWithFormat:@"%C", VLCKeyToCocoa( i_key )]];
    [o_mi_fwd5m setKeyEquivalentModifierMask: VLCModifiersToCocoa(i_key)];
339
    i_key = config_GetInt( p_intf, "key-jump-long" );
340 341
    [o_mi_bwd5m setKeyEquivalent: [NSString stringWithFormat:@"%C", VLCKeyToCocoa( i_key )]];
    [o_mi_bwd5m setKeyEquivalentModifierMask: VLCModifiersToCocoa(i_key)];
342 343 344 345 346 347
    i_key = config_GetInt( p_intf, "key-vol-up" );
    [o_mi_vol_up setKeyEquivalent: [NSString stringWithFormat:@"%C", VLCKeyToCocoa( i_key )]];
    [o_mi_vol_up setKeyEquivalentModifierMask: VLCModifiersToCocoa(i_key)];
    i_key = config_GetInt( p_intf, "key-vol-down" );
    [o_mi_vol_down setKeyEquivalent: [NSString stringWithFormat:@"%C", VLCKeyToCocoa( i_key )]];
    [o_mi_vol_down setKeyEquivalentModifierMask: VLCModifiersToCocoa(i_key)];
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
348 349 350
    i_key = config_GetInt( p_intf, "key-vol-mute" );
    [o_mi_mute setKeyEquivalent: [NSString stringWithFormat:@"%C", VLCKeyToCocoa( i_key )]];
    [o_mi_mute setKeyEquivalentModifierMask: VLCModifiersToCocoa(i_key)];
351 352 353
    i_key = config_GetInt( p_intf, "key-fullscreen" );
    [o_mi_fullscreen setKeyEquivalent: [NSString stringWithFormat:@"%C", VLCKeyToCocoa( i_key )]];
    [o_mi_fullscreen setKeyEquivalentModifierMask: VLCModifiersToCocoa(i_key)];
354 355 356
    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)];
357

358
    var_Create( p_intf, "intf-change", VLC_VAR_BOOL );
359

360
    [self setSubmenusEnabled: FALSE];
361
    [o_volumeslider setEnabled: YES];
362
    [self manageVolumeSlider];
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
363
    [o_window setDelegate: self];
364
 
365
    b_restore_size = false;
366 367 368 369 370

    // Set that here as IB seems to be buggy
    [o_window setContentMinSize:NSMakeSize(338., 30.)];

    if( [o_window contentRectForFrameRect:[o_window frame]].size.height <= 169. )
371 372
    {
        b_small_window = YES;
373 374 375
        [o_window setFrame: NSMakeRect( [o_window frame].origin.x,
            [o_window frame].origin.y, [o_window frame].size.width,
            [o_window minSize].height ) display: YES animate:YES];
376 377 378 379 380
        [o_playlist_view setAutoresizesSubviews: NO];
    }
    else
    {
        b_small_window = NO;
381 382
        NSRect contentRect = [o_window contentRectForFrameRect:[o_window frame]];
        [o_playlist_view setFrame: NSMakeRect( 0, 0, contentRect.size.width, contentRect.size.height - [o_window contentMinSize].height )];
383 384 385 386
        [o_playlist_view setNeedsDisplay:YES];
        [o_playlist_view setAutoresizesSubviews: YES];
        [[o_window contentView] addSubview: o_playlist_view];
    }
387

388
    [self updateTogglePlaylistState];
Jérome Decoodt's avatar
Jérome Decoodt committed
389

390
    o_size_with_playlist = [o_window contentRectForFrameRect:[o_window frame]].size;
391

392
    p_playlist = pl_Yield( p_intf );
393

394
    var_Create( p_playlist, "fullscreen", VLC_VAR_BOOL | VLC_VAR_DOINHERIT);
395
    val.b_bool = false;
396

397
    var_AddCallback( p_playlist, "fullscreen", FullscreenChanged, self);
398
    var_AddCallback( p_intf->p_libvlc, "intf-show", ShowController, self);
399

400
    pl_Release( p_intf );
401
 
402 403
    var_Create( p_intf, "interaction", VLC_VAR_ADDRESS );
    var_AddCallback( p_intf, "interaction", InteractCallback, self );
404
    p_intf->b_interaction = true;
405

406
    /* update the playmode stuff */
407
    p_intf->p_sys->b_playmode_update = true;
408

409 410 411 412
    [[NSNotificationCenter defaultCenter] addObserver: self
                                             selector: @selector(refreshVoutDeviceMenu:)
                                                 name: NSApplicationDidChangeScreenParametersNotification
                                               object: nil];
413 414 415 416 417 418 419 420 421 422 423

    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];
    
424
    nib_main_loaded = TRUE;
425 426
}

427
- (void)applicationWillFinishLaunching:(NSNotification *)o_notification
428
{
429 430
    o_msg_lock = [[NSLock alloc] init];
    o_msg_arr = [[NSMutableArray arrayWithCapacity: 200] retain];
431

432 433 434 435
    /* FIXME: don't poll */
    interfaceTimer = [[NSTimer scheduledTimerWithTimeInterval: 0.5
                                     target: self selector: @selector(manageIntf:)
                                   userInfo: nil repeats: FALSE] retain];
436

437 438
    /* Note: we use the pthread API to support pre-10.5 */
    pthread_create( &manage_thread, NULL, ManageThread, self );
439

440 441
    [o_controls setupVarMenuItem: o_mi_add_intf target: (vlc_object_t *)p_intf
        var: "intf-add" selector: @selector(toggleVar:)];
442

443 444
    /* check whether the user runs a valid version of OSX; alert is auto-released */
    if( MACOS_VERSION < 10.4f )
445
    {
446 447 448 449 450 451 452 453 454 455
        NSAlert *ourAlert;
        int i_returnValue;
        ourAlert = [NSAlert alertWithMessageText: _NS("Your version of Mac OS X is not supported")
                        defaultButton: _NS("Quit")
                      alternateButton: NULL
                          otherButton: NULL
            informativeTextWithFormat: _NS("VLC media player requires Mac OS X 10.4 or higher.")];
        [ourAlert setAlertStyle: NSCriticalAlertStyle];
        i_returnValue = [ourAlert runModal];
        [NSApp terminate: self];
456 457
    }

458 459
    vlc_thread_set_priority( p_intf, VLC_THREAD_PRIORITY_LOW );
}
460

461
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
462
{
463 464 465 466 467 468 469 470 471 472 473 474 475 476
#ifdef UPDATE_CHECK
    /* Check for update silently on startup */
    if( !nib_update_loaded )
        nib_update_loaded = [NSBundle loadNibNamed:@"Update" owner:self];

    if([o_update shouldCheckForUpdate])
        [NSThread detachNewThreadSelector:@selector(checkForUpdate) toTarget:o_update withObject:nil];
#endif

    /* Handle sleep notification */
    [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector:@selector(computerWillSleep:)
           name:NSWorkspaceWillSleepNotification object:nil];

    [NSThread detachNewThreadSelector:@selector(lookForCrashLog) toTarget:self withObject:nil];
477 478
}

479
- (void)initStrings
480
{
Felix Paul Kühne's avatar
Felix Paul Kühne committed
481
    [o_window setTitle: _NS("VLC media player")];
482
    [self setScrollField:_NS("VLC media player") stopAfter:-1];
483

Jon Lech Johansen's avatar
Jon Lech Johansen committed
484 485
    /* button controls */
    [o_btn_prev setToolTip: _NS("Previous")];
486
    [o_btn_rewind setToolTip: _NS("Rewind")];
Jon Lech Johansen's avatar
Jon Lech Johansen committed
487 488
    [o_btn_play setToolTip: _NS("Play")];
    [o_btn_stop setToolTip: _NS("Stop")];
489
    [o_btn_ff setToolTip: _NS("Fast Forward")];
Jon Lech Johansen's avatar
Jon Lech Johansen committed
490
    [o_btn_next setToolTip: _NS("Next")];
491
    [o_btn_fullscreen setToolTip: _NS("Fullscreen")];
492 493
    [o_volumeslider setToolTip: _NS("Volume")];
    [o_timeslider setToolTip: _NS("Position")];
494
    [o_btn_playlist setToolTip: _NS("Playlist")];
495

Jérome Decoodt's avatar
Jérome Decoodt committed
496
    /* messages panel */
497
    [o_msgs_panel setTitle: _NS("Messages")];
498
    [o_msgs_btn_crashlog setTitle: _NS("Open CrashLog...")];
499

Jon Lech Johansen's avatar
Jon Lech Johansen committed
500
    /* main menu */
501 502
    [o_mi_about setTitle: [_NS("About VLC media player") \
        stringByAppendingString: @"..."]];
503
    [o_mi_checkForUpdate setTitle: _NS("Check for Update...")];
504
    [o_mi_prefs setTitle: _NS("Preferences...")];
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
505 506
    [o_mi_add_intf setTitle: _NS("Add Interface")];
    [o_mu_add_intf setTitle: _NS("Add Interface")];
507
    [o_mi_services setTitle: _NS("Services")];
508
    [o_mi_hide setTitle: _NS("Hide VLC")];
509 510
    [o_mi_hide_others setTitle: _NS("Hide Others")];
    [o_mi_show_all setTitle: _NS("Show All")];
511
    [o_mi_quit setTitle: _NS("Quit VLC")];
512

Derk-Jan Hartman's avatar
ALL:  
Derk-Jan Hartman committed
513
    [o_mu_file setTitle: _ANS("1:File")];
514 515
    [o_mi_open_generic setTitle: _NS("Open File...")];
    [o_mi_open_file setTitle: _NS("Quick Open File...")];
516 517
    [o_mi_open_disc setTitle: _NS("Open Disc...")];
    [o_mi_open_net setTitle: _NS("Open Network...")];
518
    [o_mi_open_capture setTitle: _NS("Open Capture Device...")];
519 520
    [o_mi_open_recent setTitle: _NS("Open Recent")];
    [o_mi_open_recent_cm setTitle: _NS("Clear Menu")];
521
    [o_mi_open_wizard setTitle: _NS("Streaming/Exporting Wizard...")];
522 523 524 525 526 527 528 529

    [o_mu_edit setTitle: _NS("Edit")];
    [o_mi_cut setTitle: _NS("Cut")];
    [o_mi_copy setTitle: _NS("Copy")];
    [o_mi_paste setTitle: _NS("Paste")];
    [o_mi_clear setTitle: _NS("Clear")];
    [o_mi_select_all setTitle: _NS("Select All")];

530
    [o_mu_controls setTitle: _NS("Playback")];
531
    [o_mi_play setTitle: _NS("Play")];
532 533 534
    [o_mi_stop setTitle: _NS("Stop")];
    [o_mi_faster setTitle: _NS("Faster")];
    [o_mi_slower setTitle: _NS("Slower")];
Christophe Massiot's avatar
Christophe Massiot committed
535
    [o_mi_previous setTitle: _NS("Previous")];
536
    [o_mi_next setTitle: _NS("Next")];
537 538 539
    [o_mi_random setTitle: _NS("Random")];
    [o_mi_repeat setTitle: _NS("Repeat One")];
    [o_mi_loop setTitle: _NS("Repeat All")];
540 541
    [o_mi_fwd setTitle: _NS("Step Forward")];
    [o_mi_bwd setTitle: _NS("Step Backward")];
542

543
    [o_mi_program setTitle: _NS("Program")];
544
    [o_mu_program setTitle: _NS("Program")];
545
    [o_mi_title setTitle: _NS("Title")];
546
    [o_mu_title setTitle: _NS("Title")];
547
    [o_mi_chapter setTitle: _NS("Chapter")];
548
    [o_mu_chapter setTitle: _NS("Chapter")];
Jérome Decoodt's avatar
Jérome Decoodt committed
549

550
    [o_mu_audio setTitle: _NS("Audio")];
Jon Lech Johansen's avatar
Jon Lech Johansen committed
551 552
    [o_mi_vol_up setTitle: _NS("Volume Up")];
    [o_mi_vol_down setTitle: _NS("Volume Down")];
553
    [o_mi_mute setTitle: _NS("Mute")];
554 555 556 557 558 559
    [o_mi_audiotrack setTitle: _NS("Audio Track")];
    [o_mu_audiotrack setTitle: _NS("Audio Track")];
    [o_mi_channels setTitle: _NS("Audio Channels")];
    [o_mu_channels setTitle: _NS("Audio Channels")];
    [o_mi_device setTitle: _NS("Audio Device")];
    [o_mu_device setTitle: _NS("Audio Device")];
560 561
    [o_mi_visual setTitle: _NS("Visualizations")];
    [o_mu_visual setTitle: _NS("Visualizations")];
Jérome Decoodt's avatar
Jérome Decoodt committed
562

563
    [o_mu_video setTitle: _NS("Video")];
564 565 566
    [o_mi_half_window setTitle: _NS("Half Size")];
    [o_mi_normal_window setTitle: _NS("Normal Size")];
    [o_mi_double_window setTitle: _NS("Double Size")];
567
    [o_mi_fittoscreen setTitle: _NS("Fit to Screen")];
568
    [o_mi_fullscreen setTitle: _NS("Fullscreen")];
569
    [o_mi_floatontop setTitle: _NS("Float on Top")];
570
    [o_mi_snapshot setTitle: _NS("Snapshot")];
571 572
    [o_mi_videotrack setTitle: _NS("Video Track")];
    [o_mu_videotrack setTitle: _NS("Video Track")];
573 574
    [o_mi_aspect_ratio setTitle: _NS("Aspect-ratio")];
    [o_mu_aspect_ratio setTitle: _NS("Aspect-ratio")];
575 576
    [o_mi_crop setTitle: _NS("Crop")];
    [o_mu_crop setTitle: _NS("Crop")];
577 578
    [o_mi_screen setTitle: _NS("Fullscreen Video Device")];
    [o_mu_screen setTitle: _NS("Fullscreen Video Device")];
579 580
    [o_mi_subtitle setTitle: _NS("Subtitles Track")];
    [o_mu_subtitle setTitle: _NS("Subtitles Track")];
581
    [o_mi_deinterlace setTitle: _NS("Deinterlace")];
582
    [o_mu_deinterlace setTitle: _NS("Deinterlace")];
Benjamin Pracht's avatar
Benjamin Pracht committed
583 584
    [o_mi_ffmpeg_pp setTitle: _NS("Post processing")];
    [o_mu_ffmpeg_pp setTitle: _NS("Post processing")];
585 586

    [o_mu_window setTitle: _NS("Window")];
587 588
    [o_mi_minimize setTitle: _NS("Minimize Window")];
    [o_mi_close_window setTitle: _NS("Close Window")];
589 590 591 592 593 594 595 596
    [o_mi_controller setTitle: _NS("Controller...")];
    [o_mi_equalizer setTitle: _NS("Equalizer...")];
    [o_mi_extended setTitle: _NS("Extended Controls...")];
    [o_mi_bookmarks setTitle: _NS("Bookmarks...")];
    [o_mi_playlist setTitle: _NS("Playlist...")];
    [o_mi_info setTitle: _NS("Media Information...")];
    [o_mi_messages setTitle: _NS("Messages...")];
    [o_mi_errorsAndWarnings setTitle: _NS("Errors and Warnings...")];
597

598 599
    [o_mi_bring_atf setTitle: _NS("Bring All to Front")];

600
    [o_mu_help setTitle: _NS("Help")];
601
    [o_mi_help setTitle: _NS("VLC media player Help...")];
602
    [o_mi_readme setTitle: _NS("ReadMe / FAQ...")];
603
    [o_mi_license setTitle: _NS("License")];
604 605 606 607
    [o_mi_documentation setTitle: _NS("Online Documentation...")];
    [o_mi_website setTitle: _NS("VideoLAN Website...")];
    [o_mi_donation setTitle: _NS("Make a donation...")];
    [o_mi_forum setTitle: _NS("Online Forum...")];
608

609
    /* dock menu */
610
    [o_dmi_play setTitle: _NS("Play")];
611
    [o_dmi_stop setTitle: _NS("Stop")];
612 613
    [o_dmi_next setTitle: _NS("Next")];
    [o_dmi_previous setTitle: _NS("Previous")];
614
    [o_dmi_mute setTitle: _NS("Mute")];
615
 
616 617 618 619 620 621 622 623 624 625
    /* vout menu */
    [o_vmi_play setTitle: _NS("Play")];
    [o_vmi_stop setTitle: _NS("Stop")];
    [o_vmi_prev setTitle: _NS("Previous")];
    [o_vmi_next setTitle: _NS("Next")];
    [o_vmi_volup setTitle: _NS("Volume Up")];
    [o_vmi_voldown setTitle: _NS("Volume Down")];
    [o_vmi_mute setTitle: _NS("Mute")];
    [o_vmi_fullscreen setTitle: _NS("Fullscreen")];
    [o_vmi_snapshot setTitle: _NS("Snapshot")];
626 627 628 629 630 631 632

    /* crash reporter panel */
    [o_crashrep_send_btn setTitle: _NS("Send")];
    [o_crashrep_dontSend_btn setTitle: _NS("Don't Send")];
    [o_crashrep_title_txt setStringValue: _NS("VLC crashed previously")];
    [o_crashrep_win setTitle: _NS("VLC crashed previously")];
    [o_crashrep_desc_txt setStringValue: _NS("Do you want to send details on the crash to VLC's development team?\n\nIf you want, you can enter a few lines on what you did before VLC crashed along with other helpful information: a link to download a sample file, a URL of a network stream, ...")];
633 634
}

635 636 637 638
#pragma mark -
#pragma mark Termination

- (void)applicationWillTerminate:(NSNotification *)notification
639
{
640 641 642 643 644
    playlist_t * p_playlist;
    vout_thread_t * p_vout;
    int returnedValue = 0;
 
    msg_Dbg( p_intf, "Terminating" );
645

646 647
    /* Make sure the manage_thread won't call -terminate: again */
    pthread_cancel( manage_thread );
648

649 650
    /* Make sure the intf object is getting killed */
    vlc_object_kill( p_intf );
Jérome Decoodt's avatar
Jérome Decoodt committed
651

652 653
    /* Make sure our manage_thread ends */
    pthread_join( manage_thread, NULL );
654

655 656 657 658 659 660 661 662 663 664
    /* Make sure the interfaceTimer is destroyed */
    [interfaceTimer invalidate];
    [interfaceTimer release];
    interfaceTimer = nil;

    /* make sure that the current volume is saved */
    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])
665
    {
666
        [o_extended savePrefs];
667
    }
668 669 670
 
    p_intf->b_interaction = false;
    var_DelCallback( p_intf, "interaction", InteractCallback, self );
671

672 673
    /* remove global observer watching for vout device changes correctly */
    [[NSNotificationCenter defaultCenter] removeObserver: self];
Jérome Decoodt's avatar
Jérome Decoodt committed
674

675 676
    [o_update end];

677 678
    /* release some other objects here, because it isn't sure whether dealloc
     * will be called later on */
Derk-Jan Hartman's avatar
-  
Derk-Jan Hartman committed
679

680 681
    if( nib_about_loaded )
        [o_about release];
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
682

683
    if( nib_prefs_loaded )
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
684
    {
685 686 687
        [o_sprefs release];
        [o_prefs release];
    }
688

689 690 691 692 693 694
    if( nib_open_loaded )
        [o_open release];

    if( nib_extended_loaded )
    {
        [o_extended release];
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
695
    }
696 697 698 699 700

    if( nib_bookmarks_loaded )
        [o_bookmarks release];

    if( o_info )
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
701
    {
702 703
        [o_info stopTimers];
        [o_info release];
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
704 705
    }

706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736
    if( nib_wizard_loaded )
        [o_wizard release];

    [crashLogURLConnection cancel];
    [crashLogURLConnection release];
 
    [o_embedded_list release];
    [o_interaction_list release];
    [o_eyetv release];

    [o_img_pause_pressed release];
    [o_img_play_pressed release];
    [o_img_pause release];
    [o_img_play release];

    [o_msg_arr removeAllObjects];
    [o_msg_arr release];

    [o_msg_lock release];

    /* write cached user defaults to disk */
    [[NSUserDefaults standardUserDefaults] synchronize];

    /* 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_Yield( p_intf );
    vlc_object_kill( p_playlist );
    pl_Release( p_intf );

    vlc_object_kill( p_intf->p_libvlc );

737 738
    [self setIntf:nil];

739 740 741 742
    /* Go back to Run() and make libvlc exit properly */
    if( jmpbuffer )
        longjmp( jmpbuffer, 1 );
    /* not reached */
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
743 744
}

745 746
#pragma mark -
#pragma mark Toolbar delegate
747

748 749 750 751 752 753 754 755 756 757 758 759
/* Our item identifiers */
static NSString * VLCToolbarMediaControl     = @"VLCToolbarMediaControl";

- (NSArray *)toolbarAllowedItemIdentifiers:(NSToolbar *)toolbar
{
    return [NSArray arrayWithObjects:
//                        NSToolbarCustomizeToolbarItemIdentifier,
//                        NSToolbarFlexibleSpaceItemIdentifier,
//                        NSToolbarSpaceItemIdentifier,
//                        NSToolbarSeparatorItemIdentifier,
                        VLCToolbarMediaControl,
                        nil ];
760 761
}

762
- (NSArray *) toolbarDefaultItemIdentifiers: (NSToolbar *) toolbar
763
{
764 765 766 767
    return [NSArray arrayWithObjects:
                        VLCToolbarMediaControl,
                        nil ];
}
768

769 770 771
- (NSToolbarItem *) toolbar:(NSToolbar *)toolbar itemForItemIdentifier:(NSString *)itemIdentifier willBeInsertedIntoToolbar:(BOOL)flag
{
    NSToolbarItem *toolbarItem = [[[NSToolbarItem alloc] initWithItemIdentifier: itemIdentifier] autorelease];
772

773 774 775 776 777
 
    if( [itemIdentifier isEqual: VLCToolbarMediaControl] )
    {
        [toolbarItem setLabel:@"Media Controls"];
        [toolbarItem setPaletteLabel:@"Media Controls"];
778

779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848
        NSSize size = toolbarMediaControl.frame.size;
        [toolbarItem setView:toolbarMediaControl];
        [toolbarItem setMinSize:size];
        size.width += 1000.;
        [toolbarItem setMaxSize:size];

        // Hack: For some reason we need to make sure
        // that the those element are on top
        // Add them again will put them frontmost
        [toolbarMediaControl addSubview:o_scrollfield];
        [toolbarMediaControl addSubview:o_timeslider];
        [toolbarMediaControl addSubview:o_timefield];
        [toolbarMediaControl addSubview:o_main_pgbar];

        /* TODO: setup a menu */
    }
    else
    {
        /* itemIdentifier referred to a toolbar item that is not
         * provided or supported by us or Cocoa
         * Returning nil will inform the toolbar
         * that this kind of item is not supported */
        toolbarItem = nil;
    }
    return toolbarItem;
}

#pragma mark -
#pragma mark Other notification

- (void)controlTintChanged
{
    BOOL b_playing = NO;
    
    if( [o_btn_play alternateImage] == o_img_play_pressed )
        b_playing = YES;
    
    if( [NSColor currentControlTint] == NSGraphiteControlTint )
    {
        o_img_play_pressed = [NSImage imageNamed: @"play_graphite"];
        o_img_pause_pressed = [NSImage imageNamed: @"pause_graphite"];
        
        [o_btn_prev setAlternateImage: [NSImage imageNamed: @"previous_graphite"]];
        [o_btn_rewind setAlternateImage: [NSImage imageNamed: @"skip_previous_graphite"]];
        [o_btn_stop setAlternateImage: [NSImage imageNamed: @"stop_graphite"]];
        [o_btn_ff setAlternateImage: [NSImage imageNamed: @"skip_forward_graphite"]];
        [o_btn_next setAlternateImage: [NSImage imageNamed: @"next_graphite"]];
        [o_btn_fullscreen setAlternateImage: [NSImage imageNamed: @"fullscreen_graphite"]];
        [o_btn_playlist setAlternateImage: [NSImage imageNamed: @"playlistdrawer_graphite"]];
        [o_btn_equalizer setAlternateImage: [NSImage imageNamed: @"equalizerdrawer_graphite"]];
    }
    else
    {
        o_img_play_pressed = [NSImage imageNamed: @"play_blue"];
        o_img_pause_pressed = [NSImage imageNamed: @"pause_blue"];
        
        [o_btn_prev setAlternateImage: [NSImage imageNamed: @"previous_blue"]];
        [o_btn_rewind setAlternateImage: [NSImage imageNamed: @"skip_previous_blue"]];
        [o_btn_stop setAlternateImage: [NSImage imageNamed: @"stop_blue"]];
        [o_btn_ff setAlternateImage: [NSImage imageNamed: @"skip_forward_blue"]];
        [o_btn_next setAlternateImage: [NSImage imageNamed: @"next_blue"]];
        [o_btn_fullscreen setAlternateImage: [NSImage imageNamed: @"fullscreen_blue"]];
        [o_btn_playlist setAlternateImage: [NSImage imageNamed: @"playlistdrawer_blue"]];
        [o_btn_equalizer setAlternateImage: [NSImage imageNamed: @"equalizerdrawer_blue"]];
    }
    
    if( b_playing )
        [o_btn_play setAlternateImage: o_img_play_pressed];
    else
        [o_btn_play setAlternateImage: o_img_pause_pressed];
849 850
}

851 852 853 854 855 856 857 858 859 860 861
/* Listen to the remote in exclusive mode, only when VLC is the active
   application */
- (void)applicationDidBecomeActive:(NSNotification *)aNotification
{
    [o_remote startListening: self];
}
- (void)applicationDidResignActive:(NSNotification *)aNotification
{
    [o_remote stopListening: self];
}

862 863 864 865
/* Triggered when the computer goes to sleep */
- (void)computerWillSleep: (NSNotification *)notification
{
    /* Pause */
866
    if( p_intf->p_sys->i_play_status == PLAYING_S )
867 868 869 870 871 872 873
    {
        vlc_value_t val;
        val.i_int = config_GetInt( p_intf, "key-play-pause" );
        var_Set( p_intf->p_libvlc, "key-pressed", val );
    }
}

874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900
#pragma mark -
#pragma mark File opening

- (BOOL)application:(NSApplication *)o_app openFile:(NSString *)o_filename
{
    BOOL b_autoplay = config_GetInt( VLCIntf, "macosx-autoplay" );
    NSDictionary *o_dic = [NSDictionary dictionaryWithObjectsAndKeys: o_filename, @"ITEM_URL", nil];
    if( b_autoplay )
        [o_playlist appendArray: [NSArray arrayWithObject: o_dic] atPos: -1 enqueue: NO];
    else
        [o_playlist appendArray: [NSArray arrayWithObject: o_dic] atPos: -1 enqueue: YES];

    return( TRUE );
}

/* When user click in the Dock icon our double click in the finder */
- (BOOL)applicationShouldHandleReopen:(NSApplication *)theApplication hasVisibleWindows:(BOOL)hasVisibleWindows
{    
    if(!hasVisibleWindows)
        [o_window makeKeyAndOrderFront:self];

    return YES;
}

#pragma mark -
#pragma mark Apple Remote Control

901 902
/* Helper method for the remote control interface in order to trigger forward/backward and volume
   increase/decrease as long as the user holds the left/right, plus/minus button */
903
- (void) executeHoldActionForRemoteButton: (NSNumber*) buttonIdentifierNumber
904
{
905
    if(b_remote_button_hold)
906
    {
907
        switch([buttonIdentifierNumber intValue])
908
        {
909
            case kRemoteButtonRight_Hold:
910
                  [o_controls forward: self];
911 912
            break;
            case kRemoteButtonLeft_Hold:
913 914 915 916 917 918 919
                  [o_controls backward: self];
            break;
            case kRemoteButtonVolume_Plus_Hold:
                [o_controls volumeUp: self];
            break;
            case kRemoteButtonVolume_Minus_Hold:
                [o_controls volumeDown: self];
920
            break;
921
        }
922
        if(b_remote_button_hold)
923
        {
924
            /* trigger event */
925
            [self performSelector:@selector(executeHoldActionForRemoteButton:)
926
                         withObject:buttonIdentifierNumber
927
                         afterDelay:0.25];
928 929 930 931
        }
    }
}

932
/* Apple Remote callback */
933 934 935
- (void) appleRemoteButton: (AppleRemoteEventIdentifier)buttonIdentifier
               pressedDown: (BOOL) pressedDown
                clickCount: (unsigned int) count
936 937 938 939
{
    switch( buttonIdentifier )
    {
        case kRemoteButtonPlay:
940
            if(count >= 2) {
941 942 943
                [o_controls toogleFullscreen:self];
            } else {
                [o_controls play: self];
944
            }
945
            break;
Eric Petit's avatar
Eric Petit committed
946
        case kRemoteButtonVolume_Plus:
947
            [o_controls volumeUp: self];
Eric Petit's avatar
Eric Petit committed
948 949
            break;
        case kRemoteButtonVolume_Minus:
950
            [o_controls volumeDown: self];
Eric Petit's avatar
Eric Petit committed
951
            break;
952 953 954 955 956 957 958 959
        case kRemoteButtonRight:
            [o_controls next: self];
            break;
        case kRemoteButtonLeft:
            [o_controls prev: self];
            break;
        case kRemoteButtonRight_Hold:
        case kRemoteButtonLeft_Hold:
960 961
        case kRemoteButtonVolume_Plus_Hold:
        case kRemoteButtonVolume_Minus_Hold:
Felix Paul Kühne's avatar