intf.m 74.9 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

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 55
#import "controls.h"
#import "about.h"
#import "open.h"
#import "wizard.h"
#import "extended.h"
#import "bookmarks.h"
#import "sfilters.h"
#import "interaction.h"
#import "embeddedwindow.h"
#import "update.h"
#import "AppleRemote.h"
56
#import "eyetv.h"
57
#import "simple_prefs.h"
58

59
#import <vlc_input.h>
60
#import <vlc_interface.h>
61

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

67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
/* Quick hack */
/*****************************************************************************
 * VLCApplication implementation (this hack is really disgusting now,
 *                                feel free to fix.)
 *****************************************************************************/
@interface VLCApplication : NSApplication
{
   libvlc_int_t *o_libvlc;
}
- (void)setVLC: (libvlc_int_t *)p_libvlc;
@end


@implementation VLCApplication
- (void)setVLC: (libvlc_int_t *) p_libvlc
{
    o_libvlc = p_libvlc;
}
- (void)terminate: (id)sender
{
    vlc_object_kill( o_libvlc );
    [super terminate: sender];
}
@end

92 93 94 95
/*****************************************************************************
 * OpenIntf: initialize interface
 *****************************************************************************/
int E_(OpenIntf) ( vlc_object_t *p_this )
Jérome Decoodt's avatar
Jérome Decoodt committed
96
{
97 98 99 100 101 102 103 104 105
    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
106

107
    p_intf->p_sys->o_pool = [[NSAutoreleasePool alloc] init];
108

109
    p_intf->p_sys->o_sendport = [[NSPort port] retain];
110
    p_intf->p_sys->p_sub = msg_Subscribe( p_intf, MSG_QUEUE_NORMAL );
111
    p_intf->b_play = VLC_TRUE;
112
    p_intf->pf_run = Run;
113
    p_intf->b_should_run_on_first_thread = VLC_TRUE;
114 115 116 117 118 119 120 121 122 123

    return( 0 );
}

/*****************************************************************************
 * CloseIntf: destroy interface
 *****************************************************************************/
void E_(CloseIntf) ( vlc_object_t *p_this )
{
    intf_thread_t *p_intf = (intf_thread_t*) p_this;
Jérome Decoodt's avatar
Jérome Decoodt committed
124

125 126
    [[VLCMain sharedInstance] setIntf: nil];
    
127
    msg_Unsubscribe( p_intf, p_intf->p_sys->p_sub );
Jérome Decoodt's avatar
Jérome Decoodt committed
128

129 130
    [p_intf->p_sys->o_sendport release];
    [p_intf->p_sys->o_pool release];
Jérome Decoodt's avatar
Jérome Decoodt committed
131

132 133 134
    free( p_intf->p_sys );
}

135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
/*****************************************************************************
 * KillerThread: Thread that kill the application
 *****************************************************************************/
static void * KillerThread( void *user_data )
{
    NSAutoreleasePool * o_pool = [[NSAutoreleasePool alloc] init];

    intf_thread_t *p_intf = user_data;
    
    vlc_object_lock ( p_intf );
    while( vlc_object_alive( p_intf ) )
        vlc_object_wait( p_intf );
    vlc_object_unlock( p_intf );

    msg_Dbg( p_intf, "Killing the Mac OS X module\n" );

    /* We are dead, terminate */
    [NSApp terminate: nil];
    [o_pool release];
    return NULL;
}
156 157 158
/*****************************************************************************
 * Run: main loop
 *****************************************************************************/
159 160
jmp_buf jmpbuffer;

161 162
static void Run( intf_thread_t *p_intf )
{
163 164
    sigset_t set;

165 166 167 168
    /* 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 );
169 170 171 172 173 174 175 176 177

    /* 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 );

178 179 180 181 182 183 184 185
    NSAutoreleasePool * o_pool = [[NSAutoreleasePool alloc] init];

    /* Install a jmpbuffer to where we can go back before the NSApp exit
     * see applicationWillTerminate: */
    /* We need that code to run on main thread */
    [VLCApplication sharedApplication];
    [NSApp setVLC: p_intf->p_libvlc];

Derk-Jan Hartman's avatar
-  
Derk-Jan Hartman committed
186
    [[VLCMain sharedInstance] setIntf: p_intf];
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
187
    [NSBundle loadNibNamed: @"MainMenu" owner: NSApp];
188

189 190 191 192
    /* Setup a thread that will monitor the module killing */
    pthread_t killer_thread;
    pthread_create( &killer_thread, NULL, KillerThread, p_intf );

193 194 195 196
    /* Install a jmpbuffer to where we can go back before the NSApp exit
     * see applicationWillTerminate: */
    if(setjmp(jmpbuffer) == 0)
        [NSApp run];
197 198

    [o_pool release];
199 200
}

201
int ExecuteOnMainThread( id target, SEL sel, void * p_arg )
202
{
203
    int i_ret = 0;
204

Derk-Jan Hartman's avatar
-  
Derk-Jan Hartman committed
205
    //NSAutoreleasePool * o_pool = [[NSAutoreleasePool alloc] init];
206 207 208

    if( [target respondsToSelector: @selector(performSelectorOnMainThread:
                                             withObject:waitUntilDone:)] )
209
    {
210 211
        [target performSelectorOnMainThread: sel
                withObject: [NSValue valueWithPointer: p_arg]
Derk-Jan Hartman's avatar
-  
Derk-Jan Hartman committed
212
                waitUntilDone: NO];
213
    }
Jérome Decoodt's avatar
Jérome Decoodt committed
214
    else if( NSApp != nil && [[VLCMain sharedInstance] respondsToSelector: @selector(getIntf)] )
215 216 217 218 219 220 221 222 223 224 225 226 227
    {
        NSValue * o_v1;
        NSValue * o_v2;
        NSArray * o_array;
        NSPort * o_recv_port;
        NSInvocation * o_inv;
        NSPortMessage * o_msg;
        intf_thread_t * p_intf;
        NSConditionLock * o_lock;
        NSMethodSignature * o_sig;

        id * val[] = { &o_lock, &o_v2 };

Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
228
        p_intf = (intf_thread_t *)VLCIntf;
229 230

        o_recv_port = [[NSPort port] retain];
Jérome Decoodt's avatar
Jérome Decoodt committed
231
        o_v1 = [NSValue valueWithPointer: val];
232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253
        o_v2 = [NSValue valueWithPointer: p_arg];

        o_sig = [target methodSignatureForSelector: sel];
        o_inv = [NSInvocation invocationWithMethodSignature: o_sig];
        [o_inv setArgument: &o_v1 atIndex: 2];
        [o_inv setTarget: target];
        [o_inv setSelector: sel];

        o_array = [NSArray arrayWithObject:
            [NSData dataWithBytes: &o_inv length: sizeof(o_inv)]];
        o_msg = [[NSPortMessage alloc]
            initWithSendPort: p_intf->p_sys->o_sendport
            receivePort: o_recv_port components: o_array];

        o_lock = [[NSConditionLock alloc] initWithCondition: 0];
        [o_msg sendBeforeDate: [NSDate distantPast]];
        [o_lock lockWhenCondition: 1];
        [o_lock unlock];
        [o_lock release];

        [o_msg release];
        [o_recv_port release];
Jérome Decoodt's avatar
Jérome Decoodt committed
254
    }
255 256 257 258 259
    else
    {
        i_ret = 1;
    }

Derk-Jan Hartman's avatar
-  
Derk-Jan Hartman committed
260
    //[o_pool release];
261

262
    return( i_ret );
263 264
}

265 266 267 268
/*****************************************************************************
 * playlistChanged: Callback triggered by the intf-change playlist
 * variable, to let the intf update the playlist.
 *****************************************************************************/
269
static int PlaylistChanged( vlc_object_t *p_this, const char *psz_variable,
270 271
                     vlc_value_t old_val, vlc_value_t new_val, void *param )
{
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
272
    intf_thread_t * p_intf = VLCIntf;
273 274 275
    p_intf->p_sys->b_playlist_update = VLC_TRUE;
    p_intf->p_sys->b_intf_update = VLC_TRUE;
    p_intf->p_sys->b_playmode_update = VLC_TRUE;
276
    p_intf->p_sys->b_current_title_update = VLC_TRUE;
277 278 279 280 281 282 283 284 285 286 287 288 289
    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;
    p_intf->p_sys->b_intf_show = VLC_TRUE;
290 291 292
    return VLC_SUCCESS;
}

293 294 295 296
/*****************************************************************************
 * FullscreenChanged: Callback triggered by the fullscreen-change playlist
 * variable, to let the intf update the controller.
 *****************************************************************************/
297
static int FullscreenChanged( vlc_object_t *p_this, const char *psz_variable,
298 299 300
                     vlc_value_t old_val, vlc_value_t new_val, void *param )
{
    intf_thread_t * p_intf = VLCIntf;
301
    p_intf->p_sys->b_fullscreen_update = VLC_TRUE;
302 303 304
    return VLC_SUCCESS;
}

305 306 307 308 309 310 311 312 313 314 315
/*****************************************************************************
 * 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];
316
 
317 318
    [[NSNotificationCenter defaultCenter] postNotificationName: @"VLCNewInteractionEventNotification" object:[interface getInteractionList]
     userInfo:[NSDictionary dictionaryWithObject:o_value forKey:@"VLCDialogPointer"]];
319
 
320 321 322
    [o_pool release];
    return VLC_SUCCESS;
}
323

324 325 326
static struct
{
    unichar i_nskey;
327
    unsigned int i_vlckey;
Jérome Decoodt's avatar
Jérome Decoodt committed
328
} nskeys_to_vlckeys[] =
329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358
{
    { NSUpArrowFunctionKey, KEY_UP },
    { NSDownArrowFunctionKey, KEY_DOWN },
    { NSLeftArrowFunctionKey, KEY_LEFT },
    { NSRightArrowFunctionKey, KEY_RIGHT },
    { NSF1FunctionKey, KEY_F1 },
    { NSF2FunctionKey, KEY_F2 },
    { NSF3FunctionKey, KEY_F3 },
    { NSF4FunctionKey, KEY_F4 },
    { NSF5FunctionKey, KEY_F5 },
    { NSF6FunctionKey, KEY_F6 },
    { NSF7FunctionKey, KEY_F7 },
    { NSF8FunctionKey, KEY_F8 },
    { NSF9FunctionKey, KEY_F9 },
    { NSF10FunctionKey, KEY_F10 },
    { NSF11FunctionKey, KEY_F11 },
    { NSF12FunctionKey, KEY_F12 },
    { NSHomeFunctionKey, KEY_HOME },
    { NSEndFunctionKey, KEY_END },
    { NSPageUpFunctionKey, KEY_PAGEUP },
    { NSPageDownFunctionKey, KEY_PAGEDOWN },
    { NSTabCharacter, KEY_TAB },
    { NSCarriageReturnCharacter, KEY_ENTER },
    { NSEnterCharacter, KEY_ENTER },
    { NSBackspaceCharacter, KEY_BACKSPACE },
    { (unichar) ' ', KEY_SPACE },
    { (unichar) 0x1b, KEY_ESC },
    {0,0}
};

359
unichar VLCKeyToCocoa( unsigned int i_key )
360
{
361
    unsigned int i;
Jérome Decoodt's avatar
Jérome Decoodt committed
362

363 364 365 366 367 368 369 370 371 372 373 374 375
    for( i = 0; nskeys_to_vlckeys[i].i_vlckey != 0; i++ )
    {
        if( nskeys_to_vlckeys[i].i_vlckey == (i_key & ~KEY_MODIFIER) )
        {
            return nskeys_to_vlckeys[i].i_nskey;
        }
    }
    return (unichar)(i_key & ~KEY_MODIFIER);
}

unsigned int CocoaKeyToVLC( unichar i_key )
{
    unsigned int i;
Jérome Decoodt's avatar
Jérome Decoodt committed
376

377 378 379 380 381 382 383
    for( i = 0; nskeys_to_vlckeys[i].i_nskey != 0; i++ )
    {
        if( nskeys_to_vlckeys[i].i_nskey == i_key )
        {
            return nskeys_to_vlckeys[i].i_vlckey;
        }
    }
384 385 386 387 388 389 390 391 392 393 394 395 396 397 398
    return (unsigned int)i_key;
}

unsigned int VLCModifiersToCocoa( unsigned int i_key )
{
    unsigned int new = 0;
    if( i_key & KEY_MODIFIER_COMMAND )
        new |= NSCommandKeyMask;
    if( i_key & KEY_MODIFIER_ALT )
        new |= NSAlternateKeyMask;
    if( i_key & KEY_MODIFIER_SHIFT )
        new |= NSShiftKeyMask;
    if( i_key & KEY_MODIFIER_CTRL )
        new |= NSControlKeyMask;
    return new;
399 400
}

401
/*****************************************************************************
Jérome Decoodt's avatar
Jérome Decoodt committed
402
 * VLCMain implementation
403 404 405
 *****************************************************************************/
@implementation VLCMain

Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
406 407 408 409 410 411 412
static VLCMain *_o_sharedMainInstance = nil;

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

Jérome Decoodt's avatar
Jérome Decoodt committed
413
- (id)init
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
414
{
415 416
    if( _o_sharedMainInstance) 
    {
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
417
        [self dealloc];
418 419 420
        return _o_sharedMainInstance;
    } 
    else
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
421
        _o_sharedMainInstance = [super init];
422

423
    o_about = [[VLAboutBox alloc] init];
424
    o_prefs = [[VLCPrefs alloc] init];
425
    o_open = [[VLCOpen alloc] init];
426
    o_wizard = [[VLCWizard alloc] init];
427
    o_extended = nil;
428
    o_bookmarks = [[VLCBookmarks alloc] init];
429
    o_embedded_list = [[VLCEmbeddedList alloc] init];
430
    o_interaction_list = [[VLCInteractionList alloc] init];
431
    o_info = [[VLCInfo alloc] init];
432
    o_sfilters = nil;
433
#ifdef UPDATE_CHECK
434
    o_update = [[VLCUpdate alloc] init];
435
#endif
436 437

    i_lastShownVolume = -1;
438 439

    o_remote = [[AppleRemote alloc] init];
440
    [o_remote setClickCountEnabledButtons: kRemoteButtonPlay];
441
    [o_remote setDelegate: _o_sharedMainInstance];
442

443 444 445 446 447 448 449 450
    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
451 452 453 454 455 456 457 458 459 460 461
    return _o_sharedMainInstance;
}

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

- (intf_thread_t *)getIntf {
    return p_intf;
}

462 463
- (void)awakeFromNib
{
464
    unsigned int i_key = 0;
465
    playlist_t *p_playlist;
466
    vlc_value_t val;
467

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

471
    [self initStrings];
472
    [o_window setExcludedFromWindowsMenu: TRUE];
473 474
    [o_msgs_panel setExcludedFromWindowsMenu: TRUE];
    [o_msgs_panel setDelegate: self];
Jérome Decoodt's avatar
Jérome Decoodt committed
475

476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496
    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)];
497
    i_key = config_GetInt( p_intf, "key-jump+short" );
498 499
    [o_mi_fwd setKeyEquivalent: [NSString stringWithFormat:@"%C", VLCKeyToCocoa( i_key )]];
    [o_mi_fwd setKeyEquivalentModifierMask: VLCModifiersToCocoa(i_key)];
500
    i_key = config_GetInt( p_intf, "key-jump-short" );
501 502
    [o_mi_bwd setKeyEquivalent: [NSString stringWithFormat:@"%C", VLCKeyToCocoa( i_key )]];
    [o_mi_bwd setKeyEquivalentModifierMask: VLCModifiersToCocoa(i_key)];
503
    i_key = config_GetInt( p_intf, "key-jump+medium" );
504 505
    [o_mi_fwd1m setKeyEquivalent: [NSString stringWithFormat:@"%C", VLCKeyToCocoa( i_key )]];
    [o_mi_fwd1m setKeyEquivalentModifierMask: VLCModifiersToCocoa(i_key)];
506
    i_key = config_GetInt( p_intf, "key-jump-medium" );
507 508
    [o_mi_bwd1m setKeyEquivalent: [NSString stringWithFormat:@"%C", VLCKeyToCocoa( i_key )]];
    [o_mi_bwd1m setKeyEquivalentModifierMask: VLCModifiersToCocoa(i_key)];
509
    i_key = config_GetInt( p_intf, "key-jump+long" );
510 511
    [o_mi_fwd5m setKeyEquivalent: [NSString stringWithFormat:@"%C", VLCKeyToCocoa( i_key )]];
    [o_mi_fwd5m setKeyEquivalentModifierMask: VLCModifiersToCocoa(i_key)];
512
    i_key = config_GetInt( p_intf, "key-jump-long" );
513 514
    [o_mi_bwd5m setKeyEquivalent: [NSString stringWithFormat:@"%C", VLCKeyToCocoa( i_key )]];
    [o_mi_bwd5m setKeyEquivalentModifierMask: VLCModifiersToCocoa(i_key)];
515 516 517 518 519 520
    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)];
521 522 523
    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)];
524 525 526
    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)];
527 528 529
    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)];
530

531
    var_Create( p_intf, "intf-change", VLC_VAR_BOOL );
532

533 534
    [self setSubmenusEnabled: FALSE];
    [self manageVolumeSlider];
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
535
    [o_window setDelegate: self];
536
 
537
    b_restore_size = false;
538 539 540
    if( [o_window frame].size.height <= 200 )
    {
        b_small_window = YES;
541 542 543
        [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];
544 545 546 547 548 549 550 551 552 553 554
        [o_playlist_view setAutoresizesSubviews: NO];
    }
    else
    {
        b_small_window = NO;
        [o_playlist_view setFrame: NSMakeRect( 10, 10, [o_window frame].size.width - 20, [o_window frame].size.height - 105 )];
        [o_playlist_view setNeedsDisplay:YES];
        [o_playlist_view setAutoresizesSubviews: YES];
        [[o_window contentView] addSubview: o_playlist_view];
    }
    [self updateTogglePlaylistState];
Jérome Decoodt's avatar
Jérome Decoodt committed
555

556 557
    o_size_with_playlist = [o_window frame].size;

558
    p_playlist = pl_Yield( p_intf );
559

560 561
    /* Check if we need to start playing */
    if( p_intf->b_play )
562
    {
563
        playlist_Control( p_playlist, PLAYLIST_PLAY, VLC_FALSE );
564 565 566
    }
    var_Create( p_playlist, "fullscreen", VLC_VAR_BOOL | VLC_VAR_DOINHERIT);
    val.b_bool = VLC_FALSE;
567

568 569
    var_AddCallback( p_playlist, "fullscreen", FullscreenChanged, self);
    var_AddCallback( p_playlist, "intf-show", ShowController, self);
570

571
    vlc_object_release( p_playlist );
572
 
573 574 575
    var_Create( p_intf, "interaction", VLC_VAR_ADDRESS );
    var_AddCallback( p_intf, "interaction", InteractCallback, self );
    p_intf->b_interaction = VLC_TRUE;
576

577 578
    /* update the playmode stuff */
    p_intf->p_sys->b_playmode_update = VLC_TRUE;
579

580 581 582 583
    [[NSNotificationCenter defaultCenter] addObserver: self
                                             selector: @selector(refreshVoutDeviceMenu:)
                                                 name: NSApplicationDidChangeScreenParametersNotification
                                               object: nil];
584 585 586 587 588 589 590 591 592 593 594

    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];
    
595
    nib_main_loaded = TRUE;
596 597
}

598 599 600 601
- (void)controlTintChanged
{
    BOOL b_playing = NO;
    
602
    if( [o_btn_play alternateImage] == o_img_play_pressed )
603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634
        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 )
635
        [o_btn_play setAlternateImage: o_img_play_pressed];
636
    else
637
        [o_btn_play setAlternateImage: o_img_pause_pressed];
638 639
}

640
- (void)initStrings
641 642
{
    [o_window setTitle: _NS("VLC - Controller")];
643
    [self setScrollField:_NS("VLC media player") stopAfter:-1];
644

Jon Lech Johansen's avatar
Jon Lech Johansen committed
645 646
    /* button controls */
    [o_btn_prev setToolTip: _NS("Previous")];
647
    [o_btn_rewind setToolTip: _NS("Rewind")];
Jon Lech Johansen's avatar
Jon Lech Johansen committed
648 649
    [o_btn_play setToolTip: _NS("Play")];
    [o_btn_stop setToolTip: _NS("Stop")];
650
    [o_btn_ff setToolTip: _NS("Fast Forward")];
Jon Lech Johansen's avatar
Jon Lech Johansen committed
651
    [o_btn_next setToolTip: _NS("Next")];
652
    [o_btn_fullscreen setToolTip: _NS("Fullscreen")];
653 654
    [o_volumeslider setToolTip: _NS("Volume")];
    [o_timeslider setToolTip: _NS("Position")];
655
    [o_btn_playlist setToolTip: _NS("Playlist")];
656

Jérome Decoodt's avatar
Jérome Decoodt committed
657
    /* messages panel */
658
    [o_msgs_panel setTitle: _NS("Messages")];
659
    [o_msgs_btn_crashlog setTitle: _NS("Open CrashLog...")];
660

Jon Lech Johansen's avatar
Jon Lech Johansen committed
661
    /* main menu */
662 663
    [o_mi_about setTitle: [_NS("About VLC media player") \
        stringByAppendingString: @"..."]];
664
    [o_mi_checkForUpdate setTitle: _NS("Check for Update...")];
665
    [o_mi_prefs setTitle: _NS("Preferences...")];
666 667
    [o_mi_add_intf setTitle: _NS("Add Interface")];
    [o_mu_add_intf setTitle: _NS("Add Interface")];
668
    [o_mi_services setTitle: _NS("Services")];
669
    [o_mi_hide setTitle: _NS("Hide VLC")];
670 671
    [o_mi_hide_others setTitle: _NS("Hide Others")];
    [o_mi_show_all setTitle: _NS("Show All")];
672
    [o_mi_quit setTitle: _NS("Quit VLC")];
673

Derk-Jan Hartman's avatar
ALL:  
Derk-Jan Hartman committed
674
    [o_mu_file setTitle: _ANS("1:File")];
675 676
    [o_mi_open_generic setTitle: _NS("Open File...")];
    [o_mi_open_file setTitle: _NS("Quick Open File...")];
677 678
    [o_mi_open_disc setTitle: _NS("Open Disc...")];
    [o_mi_open_net setTitle: _NS("Open Network...")];
679 680
    [o_mi_open_recent setTitle: _NS("Open Recent")];
    [o_mi_open_recent_cm setTitle: _NS("Clear Menu")];
681
    [o_mi_open_wizard setTitle: _NS("Streaming/Exporting Wizard...")];
682 683 684 685 686 687 688 689

    [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")];

690
    [o_mu_controls setTitle: _NS("Playback")];
691
    [o_mi_play setTitle: _NS("Play")];
692 693 694
    [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
695
    [o_mi_previous setTitle: _NS("Previous")];
696
    [o_mi_next setTitle: _NS("Next")];
697 698 699
    [o_mi_random setTitle: _NS("Random")];
    [o_mi_repeat setTitle: _NS("Repeat One")];
    [o_mi_loop setTitle: _NS("Repeat All")];
700 701
    [o_mi_fwd setTitle: _NS("Step Forward")];
    [o_mi_bwd setTitle: _NS("Step Backward")];
702

703
    [o_mi_program setTitle: _NS("Program")];
704
    [o_mu_program setTitle: _NS("Program")];
705
    [o_mi_title setTitle: _NS("Title")];
706
    [o_mu_title setTitle: _NS("Title")];
707
    [o_mi_chapter setTitle: _NS("Chapter")];
708
    [o_mu_chapter setTitle: _NS("Chapter")];
Jérome Decoodt's avatar
Jérome Decoodt committed
709

710
    [o_mu_audio setTitle: _NS("Audio")];
Jon Lech Johansen's avatar
Jon Lech Johansen committed
711 712
    [o_mi_vol_up setTitle: _NS("Volume Up")];
    [o_mi_vol_down setTitle: _NS("Volume Down")];
713
    [o_mi_mute setTitle: _NS("Mute")];
714 715 716 717 718 719
    [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")];
720 721
    [o_mi_visual setTitle: _NS("Visualizations")];
    [o_mu_visual setTitle: _NS("Visualizations")];
Jérome Decoodt's avatar
Jérome Decoodt committed
722

723
    [o_mu_video setTitle: _NS("Video")];
724 725 726
    [o_mi_half_window setTitle: _NS("Half Size")];
    [o_mi_normal_window setTitle: _NS("Normal Size")];
    [o_mi_double_window setTitle: _NS("Double Size")];
727
    [o_mi_fittoscreen setTitle: _NS("Fit to Screen")];
728
    [o_mi_fullscreen setTitle: _NS("Fullscreen")];
729
    [o_mi_floatontop setTitle: _NS("Float on Top")];
730
    [o_mi_snapshot setTitle: _NS("Snapshot")];
731 732
    [o_mi_videotrack setTitle: _NS("Video Track")];
    [o_mu_videotrack setTitle: _NS("Video Track")];
733 734
    [o_mi_aspect_ratio setTitle: _NS("Aspect-ratio")];
    [o_mu_aspect_ratio setTitle: _NS("Aspect-ratio")];
735 736
    [o_mi_crop setTitle: _NS("Crop")];
    [o_mu_crop setTitle: _NS("Crop")];
737 738 739 740
    [o_mi_screen setTitle: _NS("Video Device")];
    [o_mu_screen setTitle: _NS("Video Device")];
    [o_mi_subtitle setTitle: _NS("Subtitles Track")];
    [o_mu_subtitle setTitle: _NS("Subtitles Track")];
741
    [o_mi_deinterlace setTitle: _NS("Deinterlace")];
742
    [o_mu_deinterlace setTitle: _NS("Deinterlace")];
Benjamin Pracht's avatar
Benjamin Pracht committed
743 744
    [o_mi_ffmpeg_pp setTitle: _NS("Post processing")];
    [o_mu_ffmpeg_pp setTitle: _NS("Post processing")];
745 746

    [o_mu_window setTitle: _NS("Window")];
747 748
    [o_mi_minimize setTitle: _NS("Minimize Window")];
    [o_mi_close_window setTitle: _NS("Close Window")];
749 750 751 752 753 754 755 756
    [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...")];
757

758 759
    [o_mi_bring_atf setTitle: _NS("Bring All to Front")];

760
    [o_mu_help setTitle: _NS("Help")];
761
    [o_mi_help setTitle: _NS("VLC media player Help...")];
762
    [o_mi_readme setTitle: _NS("ReadMe / FAQ...")];
763
    [o_mi_license setTitle: _NS("License")];
764 765 766 767
    [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...")];
768

769
    /* dock menu */
770
    [o_dmi_play setTitle: _NS("Play")];
771
    [o_dmi_stop setTitle: _NS("Stop")];
772 773
    [o_dmi_next setTitle: _NS("Next")];
    [o_dmi_previous setTitle: _NS("Previous")];
774
    [o_dmi_mute setTitle: _NS("Mute")];
775
 
776 777 778 779 780 781 782 783 784 785
    /* 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")];
786 787 788 789
}

- (void)applicationWillFinishLaunching:(NSNotification *)o_notification
{
790 791 792
    o_msg_lock = [[NSLock alloc] init];
    o_msg_arr = [[NSMutableArray arrayWithCapacity: 200] retain];

793
    [p_intf->p_sys->o_sendport setDelegate: self];
Jérome Decoodt's avatar
Jérome Decoodt committed
794
    [[NSRunLoop currentRunLoop]
795 796
        addPort: p_intf->p_sys->o_sendport
        forMode: NSDefaultRunLoopMode];
797

798
    [NSTimer scheduledTimerWithTimeInterval: 0.5
799
        target: self selector: @selector(manageIntf:)
800
        userInfo: nil repeats: FALSE];
801 802 803

    [NSThread detachNewThreadSelector: @selector(manage)
        toTarget: self withObject: nil];
Jérome Decoodt's avatar
Jérome Decoodt committed
804

805 806
    [o_controls setupVarMenuItem: o_mi_add_intf target: (vlc_object_t *)p_intf
        var: "intf-add" selector: @selector(toggleVar:)];
807

808
    /* check whether the user runs a valid version of OSX; alert is auto-released */
809
    if( MACOS_VERSION < 10.4f )
810 811 812 813 814 815 816 817 818 819 820 821 822
    {
        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];
    }

823
    vlc_thread_set_priority( p_intf, VLC_THREAD_PRIORITY_LOW );
824
}
Derk-Jan Hartman's avatar
-  
Derk-Jan Hartman committed
825

826 827
- (BOOL)application:(NSApplication *)o_app openFile:(NSString *)o_filename
{
828
    BOOL b_autoplay = config_GetInt( VLCIntf, "macosx-autoplay" );
829
    NSDictionary *o_dic = [NSDictionary dictionaryWithObjectsAndKeys: o_filename, @"ITEM_URL", nil];
830 831 832 833
    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];
Jérome Decoodt's avatar
Jérome Decoodt committed
834

835 836
    return( TRUE );
}
Derk-Jan Hartman's avatar
-  
Derk-Jan Hartman committed
837

838
- (NSString *)localizedString:(const char *)psz
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
839 840 841 842 843 844
{
    NSString * o_str = nil;

    if( psz != NULL )
    {
        o_str = [[[NSString alloc] initWithUTF8String: psz] autorelease];
845

846
        if( o_str == NULL )
847 848 849 850
        {
            msg_Err( VLCIntf, "could not translate: %s", psz );
            return( @"" );
        }
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
851
    }
852
    else
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
853
    {
854 855
        msg_Warn( VLCIntf, "can't translate empty strings" );
        return( @"" );
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
856 857 858 859 860
    }

    return( o_str );
}

861 862
/* When user click in the Dock icon our double click in the finder */
- (BOOL)applicationShouldHandleReopen:(NSApplication *)theApplication hasVisibleWindows:(BOOL)hasVisibleWindows
863
{    
864
    if(!hasVisibleWindows)
865 866 867 868 869
        [o_window makeKeyAndOrderFront:self];

    return YES;
}

870 871
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
872
#ifdef UPDATE_CHECK
873
    /* Check for update silently on startup */
874
    if( !nib_update_loaded )
875
        nib_update_loaded = [NSBundle loadNibNamed:@"Update" owner:self];
876

877 878
    if([o_update shouldCheckForUpdate])
        [NSThread detachNewThreadSelector:@selector(checkForUpdate) toTarget:o_update withObject:NULL];
879 880
#endif

881 882 883
    /* Handle sleep notification */
    [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector:@selector(computerWillSleep:)
           name:NSWorkspaceWillSleepNotification object:nil];
884 885
}

886 887 888 889 890 891 892 893 894 895 896
/* 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];
}

897 898 899 900
/* Triggered when the computer goes to sleep */
- (void)computerWillSleep: (NSNotification *)notification
{
    /* Pause */
901
    if( p_intf->p_sys->i_play_status == PLAYING_S )
902 903 904 905 906 907 908
    {
        vlc_value_t val;
        val.i_int = config_GetInt( p_intf, "key-play-pause" );
        var_Set( p_intf->p_libvlc, "key-pressed", val );
    }
}

909 910
/* 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 */
911
- (void) executeHoldActionForRemoteButton: (NSNumber*) buttonIdentifierNumber
912
{
913
    if(b_remote_button_hold)
914
    {
915
        switch([buttonIdentifierNumber intValue])
916
        {
917
            case kRemoteButtonRight_Hold:
918
                  [o_controls forward: self];
919 920
            break;
            case kRemoteButtonLeft_Hold:
921 922 923 924 925 926 927
                  [o_controls backward: self];
            break;
            case kRemoteButtonVolume_Plus_Hold:
                [o_controls volumeUp: self];
            break;
            case kRemoteButtonVolume_Minus_Hold:
                [o_controls volumeDown: self];
928
            break;
929
        }
930
        if(b_remote_button_hold)
931
        {
932
            /* trigger event */
933
            [self performSelector:@selector(executeHoldActionForRemoteButton:)
934
                         withObject:buttonIdentifierNumber
935
                         afterDelay:0.25];
936 937 938 939
        }
    }
}

940
/* Apple Remote callback */
941 942 943
- (void) appleRemoteButton: (AppleRemoteEventIdentifier)buttonIdentifier
               pressedDown: (BOOL) pressedDown
                clickCount: (unsigned int) count
944 945 946 947
{
    switch( buttonIdentifier )
    {
        case kRemoteButtonPlay:
948
            if(count >= 2) {
949 950 951
                [o_controls toogleFullscreen:self];
            } else {
                [o_controls play: self];
952
            }
953
            break;
Eric Petit's avatar
Eric Petit committed
954
        case kRemoteButtonVolume_Plus:
955
            [o_controls volumeUp: self];
Eric Petit's avatar
Eric Petit committed
956 957
            break;
        case kRemoteButtonVolume_Minus:
958
            [o_controls volumeDown: self];
Eric Petit's avatar
Eric Petit committed
959
            break;
960 961 962 963 964 965 966 967
        case kRemoteButtonRight:
            [o_controls next: self];
            break;
        case kRemoteButtonLeft:
            [o_controls prev: self];
            break;
        case kRemoteButtonRight_Hold:
        case kRemoteButtonLeft_Hold:
968 969
        case kRemoteButtonVolume_Plus_Hold:
        case kRemoteButtonVolume_Minus_Hold:
970
            /* simulate an event as long as the user holds the button */
971
            b_remote_button_hold = pressedDown;
972
            if( pressedDown )
973 974 975
            {
                NSNumber* buttonIdentifierNumber = [NSNumber numberWithInt: buttonIdentifier];
                [self performSelector:@selector(executeHoldActionForRemoteButton:)
976 977
                           withObject:buttonIdentifierNumber];
            }
978 979
            break;
        case kRemoteButtonMenu:
980
            [o_controls showPosition: self];
981
            break;
982 983 984 985 986 987
        default:
            /* Add here whatever you want other buttons to do */
            break;
    }
}

Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
988 989 990 991 992 993
- (char *)delocalizeString:(NSString *)id
{
    NSData * o_data = [id dataUsingEncoding: NSUTF8StringEncoding
                          allowLossyConversion: NO];
    char * psz_string;

994
    if( o_data == nil )
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
995 996 997
    {
        o_data = [id dataUsingEncoding: NSUTF8StringEncoding
                     allowLossyConversion: YES];
Jérome Decoodt's avatar
Jérome Decoodt committed
998
        psz_string = malloc( [o_data length] + 1 );
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
999 1000
        [o_data getBytes: psz_string];
        psz_string[ [o_data length] ] = '\0';
1001
        msg_Err( VLCIntf, "cannot convert to the requested encoding: %s",
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
1002 1003 1004 1005
                 psz_string );
    }
    else
    {
Jérome Decoodt's avatar
Jérome Decoodt committed
1006
        psz_string = malloc( [o_data length] + 1 );
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028
        [o_data getBytes: psz_string];
        psz_string[ [o_data length] ] = '\0';
    }

    return psz_string;
}

/* i_width is in pixels */
- (NSString *)wrapString: (NSString *)o_in_string toWidth: (int) i_width
{
    NSMutableString *o_wrapped;
    NSString *o_out_string;
    NSRange glyphRange, effectiveRange, charRange;
    NSRect lineFragmentRect;
    unsigned glyphIndex, breaksInserted = 0;

    NSTextStorage *o_storage = [[NSTextStorage alloc] initWithString: o_in_string
        attributes: [NSDictionary dictionaryWithObjectsAndKeys:
        [NSFont labelFontOfSize: 0.0], NSFontAttributeName, nil]];
    NSLayoutManager *o_layout_manager = [[NSLayoutManager alloc] init];
    NSTextContainer *o_container = [[NSTextContainer alloc]
        initWithContainerSize: NSMakeSize(i_width, 2000)];
Jérome Decoodt's avatar
Jérome Decoodt committed
1029

Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
1030 1031 1032 1033
    [o_layout_manager addTextContainer: o_container];
    [o_container release];
    [o_storage addLayoutManager: o_layout_manager];
    [o_layout_manager release];
Jérome Decoodt's avatar
Jérome Decoodt committed
1034

Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
1035 1036
    o_wrapped = [o_in_string mutableCopy];
    glyphRange = [o_layout_manager glyphRangeForTextContainer: o_container];
Jérome Decoodt's avatar
Jérome Decoodt committed
1037

Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
1038 1039 1040 1041 1042 1043
    for( glyphIndex = glyphRange.location ; glyphIndex < NSMaxRange(glyphRange) ;
            glyphIndex += effectiveRange.length) {
        lineFragmentRect = [o_layout_manager lineFragmentRectForGlyphAtIndex: glyphIndex
                                            effectiveRange: &effectiveRange];
        charRange = [o_layout_manager characterRangeForGlyphRange: effectiveRange
                                    actualGlyphRange: &effectiveRange];
1044
        if([o_wrapped lineRangeForRange:
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
1045 1046 1047 1048 1049 1050 1051 1052
                NSMakeRange(charRange.location + breaksInserted, charRange.length)].length > charRange.length) {
            [o_wrapped insertString: @"\n" atIndex: NSMaxRange(charRange) + breaksInserted];
            breaksInserted++;
        }
    }
    o_out_string = [NSString stringWithString: o_wrapped];
    [o_wrapped release];
    [o_storage release];
Jérome Decoodt's avatar
Jérome Decoodt committed
1053

Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071
    return o_out_string;
}


/*****************************************************************************
 * hasDefinedShortcutKey: Check to see if the key press is a defined VLC
 * shortcut key.  If it is, pass it off to VLC for handling and return YES,
 * otherwise ignore it and return NO (where it will get handled by Cocoa).
 *****************************************************************************/
- (BOOL)hasDefinedShortcutKey:(NSEvent *)o_event
{
    unichar key = 0;
    vlc_value_t val;
    unsigned int i_pressed_modifiers = 0;
    struct hotkey *p_hotkeys;
    int i;

    val.i_int = 0;
1072
    p_hotkeys = p_intf->p_libvlc->p_hotkeys;
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086

    i_pressed_modifiers = [o_event modifierFlags];

    if( i_pressed_modifiers & NSShiftKeyMask )
        val.i_int |= KEY_MODIFIER_SHIFT;
    if( i_pressed_modifiers & NSControlKeyMask )
        val.i_int |= KEY_MODIFIER_CTRL;
    if( i_pressed_modifiers & NSAlternateKeyMask )
        val.i_int |= KEY_MODIFIER_ALT;
    if( i_pressed_modifiers & NSCommandKeyMask )
        val.i_int |= KEY_MODIFIER_COMMAND;

    key = [[o_event charactersIgnoringModifiers] characterAtIndex: 0];

1087 1088 1089 1090 1091 1092
    switch( key )
    {
        case NSDeleteCharacter:
        case NSDeleteFunctionKey:
        case NSDeleteCharFunctionKey:
        case NSBackspaceCharacter:
1093 1094 1095 1096 1097 1098 1099
        case NSUpArrowFunctionKey:
        case NSDownArrowFunctionKey:
        case NSRightArrowFunctionKey:
        case NSLeftArrowFunctionKey:
        case NSEnterCharacter:
        case NSCarriageReturnCharacter:
            return NO;
1100 1101
    }

Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
1102 1103 1104 1105 1106 1107
    val.i_int |= CocoaKeyToVLC( key );

    for( i = 0; p_hotkeys[i].psz_action != NULL; i++ )
    {
        if( p_hotkeys[i].i_key == val.i_int )
        {
1108
            var_Set( p_intf->p_libvlc, "key-pressed", val );
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
1109 1110 1111 1112 1113 1114
            return YES;
        }
    }

    return NO;
}
1115

1116 1117
- (id)getControls
{
1118
    if( o_controls )
1119
        return o_controls;
1120

1121 1122 1123
    return nil;
}

1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145
- (id)getSimplePreferences
{
    if( !o_sprefs )
        return nil;

    if( !nib_prefs_loaded )
        nib_prefs_loaded = [NSBundle loadNibNamed:@"Preferences" owner: self];

    return o_sprefs;
}

- (id)getPreferences
{
    if( !o_prefs )
        return nil;

    if( !nib_prefs_loaded )
        nib_prefs_loaded = [NSBundle loadNibNamed:@"Preferences" owner: self];

    return o_prefs;
}

1146 1147
- (id)getPlaylist
{
1148 1149
    if( o_playlist )
        return o_playlist;
1150

1151
    return nil;
1152 1153
}

1154 1155
- (id)getInfo
{
1156
    if( o_info )
1157
        return o_info;
1158

1159 1160 1161 1162 1163
    return nil;
}

- (id)getWizard
{
1164
    if( o_wizard )
1165
        return o_wizard;
1166

1167
    return nil;
1168 1169
}

1170 1171
- (id)getBookmarks
{
1172
    if( o_bookmarks )
1173
        return o_bookmarks;
1174

1175 1176 1177
    return nil;
}

1178 1179 1180 1181
- (id)getEmbeddedList
{
    if( o_embedded_list )
        return o_embedded_list;
1182

1183 1184 1185
    return nil;
}

1186 1187 1188 1189
- (id)getInteractionList
{
    if( o_interaction_list )
        return o_interaction_list;
1190

1191 1192 1193
    return nil;
}

1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208
- (id)getMainIntfPgbar
{
    if( o_main_pgbar )
        return o_main_pgbar;

    return nil;
}

- (id)getControllerWindow
{
    if( o_window )
        return o_window;
    return nil;
}

1209 1210 1211 1212 1213
- (id)getVoutMenu
{
    return o_vout_menu;
}

1214 1215 1216 1217
- (id)getEyeTVController
{
    if( o_eyetv )
        return o_eyetv;
1218

1219 1220 1221
    return nil;
}

1222 1223
- (void)manage
{
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
1224
    playlist_t * p_playlist;
Jérome Decoodt's avatar
Jérome Decoodt committed
1225

Derk-Jan Hartman's avatar
-  
Derk-Jan Hartman committed
1226
    /* new thread requires a new pool */
1227 1228
    NSAutoreleasePool * o_pool = [[NSAutoreleasePool alloc] init];

1229 1230
    vlc_thread_set_priority( p_intf, VLC_THREAD_PRIORITY_LOW );

1231
    p_playlist = pl_Yield( p_intf );
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
1232

1233 1234 1235 1236 1237
    var_AddCallback( p_playlist, "intf-change", PlaylistChanged, self );
    var_AddCallback( p_playlist, "item-change", PlaylistChanged, self );
    var_AddCallback( p_playlist, "item-append", PlaylistChanged, self );
    var_AddCallback( p_playlist, "item-deleted", PlaylistChanged, self );
    var_AddCallback( p_playlist, "playlist-current", PlaylistChanged, self );
1238

1239
    vlc_object_release( p_playlist );
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
1240

1241
    while( (p_intf = VLCIntf) && !intf_ShouldDie( p_intf ) )
1242 1243 1244
    {
        vlc_mutex_lock( &p_intf->change_lock );

Jérome Decoodt's avatar
Jérome Decoodt committed
1245

1246
        if( p_intf->p_sys->p_input == NULL )
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
1247
        {
1248
            p_intf->p_sys->p_input = p_playlist->p_input;
Jérome Decoodt's avatar
Jérome Decoodt committed
1249

1250 1251
                /* Refresh the interface */
            if( p_intf->p_sys->p_input )
1252
            {
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
1253
                msg_Dbg( p_intf, "input has changed, refreshing interface" );
1254
                p_intf->p_sys->b_input_update = VLC_TRUE;
1255
            }
1256
        }
1257
        else if( p_intf->p_sys->p_input->b_die || p_intf->p_sys->p_input->b_dead )
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
1258 1259
        {
            /* input stopped */
1260 1261
            p_intf->p_sys->b_intf_update = VLC_TRUE;
            p_intf->p_sys->i_play_status = END_S;
1262
            msg_Dbg( p_intf, "input has stopped, refreshing interface" );
1263
            p_intf->p_sys->p_input = NULL;
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
1264
        }
1265

1266 1267 1268
        /* Manage volume status */
        [self manageVolumeSlider];

1269
        vlc_mutex_unlock( &p_intf->change_lock );
1270
        msleep( 100000 );
1271 1272 1273 1274 1275 1276
    }
    [o_pool release];
}

- (void)manageIntf:(NSTimer *)o_timer
{
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
1277
    vlc_value_t val;
1278 1279
    playlist_t * p_playlist;
    input_thread_t * p_input;
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
1280

1281
    if( p_intf->p_libvlc->b_die == VLC_TRUE )
1282 1283 1284 1285
    {
        [o_timer invalidate];
        return;
    }
1286

1287 1288 1289 1290 1291 1292 1293
    if( p_intf->p_sys->b_input_update )
    {
        /* Called when new input is opened */
        p_intf->p_sys->b_current_title_update = VLC_TRUE;
        p_intf->p_sys->b_intf_update = VLC_TRUE;
        p_intf->p_sys->b_input_update = VLC_FALSE;
    }
1294 1295 1296 1297 1298 1299 1300 1301
    if( p_intf->p_sys->b_intf_update )
    {
        vlc_bool_t b_input = VLC_FALSE;
        vlc_bool_t b_plmul = VLC_FALSE;
        vlc_bool_t b_control = VLC_FALSE;
        vlc_bool_t b_seekable = VLC_FALSE;
        vlc_bool_t b_chapters = VLC_FALSE;

1302
        playlist_t * p_playlist = pl_Yield( p_intf );
1303
    /* TODO: fix i_size use */
Clément Stenac's avatar
Clément Stenac committed
1304
        b_plmul = p_playlist->items.i_size > 1;
1305
        p_input = p_playlist->p_input;
Jérome Decoodt's avatar
Jérome Decoodt committed
1306

1307
        if( ( b_input = ( p_input != NULL ) ) )
1308
        {
1309
            /* seekable streams */
1310
            vlc_object_yield( p_input );
1311
            b_seekable = var_GetBool( p_input, "seekable" );
1312

1313
            /* check whether slow/fast motion is possible */
1314
            b_control = p_input->b_can_pace_control;
1315

1316
            /* chapters & titles */
1317 1318
            //b_chapters = p_input->stream.i_area_nb > 1;
            vlc_object_release( p_input );
1319
        }
1320
        vlc_object_release( p_playlist );
1321 1322

        [o_btn_stop setEnabled: b_input];
1323 1324
        [o_btn_ff setEnabled: b_seekable];
        [o_btn_rewind setEnabled: b_seekable];
1325 1326 1327 1328 1329
        [o_btn_prev setEnabled: (b_plmul || b_chapters)];
        [o_btn_next setEnabled: (b_plmul || b_chapters)];

        [o_timeslider setFloatValue: 0.0];
        [o_timeslider setEnabled: b_seekable];
1330 1331
        [o_timefield setStringValue: @"00:00"];
        [[[self getControls] getFSPanel] setStreamPos: 0 andTime: @"00:00"];
1332
        [[[self getControls] getFSPanel] setSeekable: b_seekable];
1333

1334 1335
        [o_embedded_window setSeekable: b_seekable];

1336 1337
        p_intf->p_sys->b_current_title_update = VLC_TRUE;
        
1338 1339
        p_intf->p_sys->b_intf_update = VLC_FALSE;
    }
Jérome Decoodt's avatar
Jérome Decoodt committed
1340

1341 1342 1343 1344 1345 1346
    if( p_intf->p_sys->b_playmode_update )
    {
        [o_playlist playModeUpdated];
        p_intf->p_sys->b_playmode_update = VLC_FALSE;
    }
    if( p_intf->p_sys->b_playlist_update )
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
1347
    {
1348
        [o_playlist playlistUpdated];
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
1349 1350
        p_intf->p_sys->b_playlist_update = VLC_FALSE;
    }
Jérome Decoodt's avatar
Jérome Decoodt committed
1351

1352
    if( p_intf->p_sys->b_fullscreen_update )
1353
    {
1354
        p_intf->p_sys->b_fullscreen_update = VLC_FALSE;
1355 1356
    }

1357 1358 1359 1360 1361 1362 1363
    if( p_intf->p_sys->b_intf_show )
    {
        [o_window makeKeyAndOrderFront: self];

        p_intf->p_sys->b_intf_show = VLC_FALSE;
    }

1364 1365 1366 1367
    p_playlist = pl_Yield( p_intf );
    p_input = p_playlist->p_input;

    if( p_input && !p_input->b_die )
1368
    {
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
1369
        vlc_value_t val;
1370
        vlc_object_yield( p_input );
1371

Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
1372
        if( p_intf->p_sys->b_current_title_update )
1373
        {
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
1374 1375
            NSString *o_temp;

1376
            if( p_playlist->status.p_item == NULL )
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
1377
            {
1378
                vlc_object_release( p_input );
1379
                vlc_object_release( p_playlist );
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
1380 1381
                return;
            }
1382 1383 1384 1385 1386 1387
            if( input_item_GetNowPlaying ( p_playlist->status.p_item->p_input ) )
                o_temp = [NSString stringWithUTF8String: 
                    input_item_GetNowPlaying ( p_playlist->status.p_item->p_input )];
            else
                o_temp = [NSString stringWithUTF8String:
                    p_playlist->status.p_item->p_input->psz_name];
1388
            [self setScrollField: o_temp stopAfter:-1];
1389
            [[[self getControls] getFSPanel] setStreamTitle: o_temp];
1390

1391
            [[o_controls getVoutView] updateTitle];
1392
 
1393
            [o_playlist updateRowSelection];
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
1394
            p_intf->p_sys->b_current_title_update = FALSE;
1395
        }
1396

1397
        if( [o_timeslider isEnabled] )
1398
        {
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
1399 1400 1401 1402
            /* Update the slider */
            vlc_value_t time;
            NSString * o_time;
            vlc_value_t pos;
1403
            char psz_time[MSTRTIME_MAX_SIZE];
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
1404
            float f_updated;
Jérome Decoodt's avatar
Jérome Decoodt committed
1405

1406
            var_Get( p_input, "position", &pos );
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
1407 1408
            f_updated = 10000. * pos.f_float;
            [o_timeslider setFloatValue: f_updated];
Jérome Decoodt's avatar
Jérome Decoodt committed
1409

1410
            var_Get( p_input, "time", &time );
Jérome Decoodt's avatar
Jérome Decoodt committed
1411

1412 1413
            o_time = [NSString stringWithUTF8String: secstotimestr( psz_time, (time.i_time / 1000000) )];

Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
1414
            [o_timefield setStringValue: o_time];
1415
            [[[self getControls] getFSPanel] setStreamPos: f_updated andTime: o_time];
1416
            [o_embedded_window setTime: o_time position: f_updated];
1417
        }
1418

1419 1420 1421
        if( p_intf->p_sys->b_volume_update )
        {
            NSString *o_text;
1422
            int i_volume_step = 0;
1423
            o_text = [NSString stringWithFormat: _NS("Volume: %d%%"), i_lastShownVolume * 400 / AOUT_VOLUME_MAX];
1424 1425
            if( i_lastShownVolume != -1 )
            [self setScrollField:o_text stopAfter:1000000];
1426
            i_volume_step = config_GetInt( p_intf->p_libvlc, "volume-step" );
1427
            [o_volumeslider setFloatValue: (float)i_lastShownVolume / i_volume_step];
1428
            [o_volumeslider setEnabled: TRUE];
1429
            [[[self getControls] getFSPanel] setVolumeLevel: (float)i_lastShownVolume / i_volume_step];
1430 1431 1432
            p_intf->p_sys->b_mute = ( i_lastShownVolume == 0 );
            p_intf->p_sys->b_volume_update = FALSE;
        }
Jérome Decoodt's avatar
Jérome Decoodt committed
1433

Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
1434
        /* Manage Playing status */
1435
        var_Get( p_input, "state", &val );
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
1436
        if( p_intf->p_sys->i_play_status != val.i_int )
1437
        {
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
1438 1439
            p_intf->p_sys->i_play_status = val.i_int;
            [self playStatusUpdated: p_intf->p_sys->i_play_status];
1440
            [o_embedded_window playStatusUpdated: p_intf->p_sys->i_play_status];
1441
        }
1442
        vlc_object_release( p_input );
1443
    }
1444
    else
1445
    {
1446
        p_intf->p_sys->i_play_status = END_S;
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
1447 1448
        p_intf->p_sys->b_intf_update = VLC_TRUE;
        [self playStatusUpdated: p_intf->p_sys->i_play_status];
1449
        [o_embedded_window playStatusUpdated: p_intf->p_sys->i_play_status];
1450
        [self setSubmenusEnabled: FALSE];
1451
    }
1452
    vlc_object_release( p_playlist );
1453 1454

    [self updateMessageArray];
1455

1456
    if( ((i_end_scroll != -1) && (mdate() > i_end_scroll)) || !p_input )
1457 1458
        [self resetScrollField];

Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
1459
    [NSTimer scheduledTimerWithTimeInterval: 0.3
1460 1461
        target: self selector: @selector(manageIntf:)
        userInfo: nil repeats: FALSE];
1462 1463
}

Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
1464 1465
- (void)setupMenus
{
1466
    playlist_t * p_playlist = pl_Yield( p_intf );
1467
    input_thread_t * p_input = p_playlist->p_input;
1468
    if( p_input != NULL )
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
1469
    {
1470
        vlc_object_yield( p_input );
1471 1472
        [o_controls setupVarMenuItem: o_mi_program target: (vlc_object_t *)p_input
            var: "program" selector: @selector(toggleVar:)];
Jérome Decoodt's avatar
Jérome Decoodt committed
1473

1474 1475
        [o_controls setupVarMenuItem: o_mi_title target: (vlc_object_t *)p_input
            var: "title" selector: @selector(toggleVar:)];
Jérome Decoodt's avatar
Jérome Decoodt committed
1476

1477 1478
        [o_controls setupVarMenuItem: o_mi_chapter target: (vlc_object_t *)p_input
            var: "chapter" selector: @selector(toggleVar:)];
Jérome Decoodt's avatar
Jérome Decoodt committed
1479

1480 1481
        [o_controls setupVarMenuItem: o_mi_audiotrack target: (vlc_object_t *)p_input
            var: "audio-es" selector: @selector(toggleVar:)];
Jérome Decoodt's avatar
Jérome Decoodt committed
1482

1483 1484
        [o_controls setupVarMenuItem: o_mi_videotrack target: (vlc_object_t *)p_input
            var: "video-es" selector: @selector(toggleVar:)];
Jérome Decoodt's avatar
Jérome Decoodt committed
1485

1486 1487
        [o_controls setupVarMenuItem: o_mi_subtitle target: (vlc_object_t *)p_input
            var: "spu-es" selector: @selector(toggleVar:)];
Jérome Decoodt's avatar
Jérome Decoodt committed
1488

1489 1490
        aout_instance_t * p_aout = vlc_object_find( p_intf, VLC_OBJECT_AOUT,
                                                    FIND_ANYWHERE );
1491
        if( p_aout != NULL )
1492 1493 1494
        {
            [o_controls setupVarMenuItem: o_mi_channels target: (vlc_object_t *)p_aout
                var: "audio-channels" selector: @selector(toggleVar:)];
Jérome Decoodt's avatar
Jérome Decoodt committed
1495

1496 1497
            [o_controls setupVarMenuItem: o_mi_device target: (vlc_object_t *)p_aout
                var: "audio-device" selector: @selector(toggleVar:)];
Jérome Decoodt's avatar
Jérome Decoodt committed
1498

1499 1500 1501 1502
            [o_controls setupVarMenuItem: o_mi_visual target: (vlc_object_t *)p_aout
                var: "visual" selector: @selector(toggleVar:)];
            vlc_object_release( (vlc_object_t *)p_aout );
        }
Jérome Decoodt's avatar
Jérome Decoodt committed
1503

1504 1505
        vout_thread_t * p_vout = vlc_object_find( p_intf, VLC_OBJECT_VOUT,
                                                            FIND_ANYWHERE );
Jérome Decoodt's avatar
Jérome Decoodt committed
1506

1507
        if( p_vout != NULL )
1508 1509
        {
            vlc_object_t * p_dec_obj;
Benjamin Pracht's avatar
Benjamin Pracht committed
1510

1511
            [o_controls setupVarMenuItem: o_mi_aspect_ratio target: (vlc_object_t *)p_vout
1512 1513
                var: "aspect-ratio" selector: @selector(toggleVar:)];

1514
            [o_controls setupVarMenuItem: o_mi_crop target: (vlc_object_t *) p_vout
1515 1516
                var: "crop" selector: @selector(toggleVar:)];

1517 1518
            [o_controls setupVarMenuItem: o_mi_screen target: (vlc_object_t *)p_vout
                var: "video-device" selector: @selector(toggleVar:)];
Jérome Decoodt's avatar
Jérome Decoodt committed
1519

1520 1521
            [o_controls setupVarMenuItem: o_mi_deinterlace target: (vlc_object_t *)p_vout
                var: "deinterlace" selector: @selector(toggleVar:)];
Benjamin Pracht's avatar
Benjamin Pracht committed
1522

1523 1524 1525 1526
            p_dec_obj = (vlc_object_t *)vlc_object_find(
                                                 (vlc_object_t *)p_vout,
                                                 VLC_OBJECT_DECODER,
                                                 FIND_PARENT );
1527
            if( p_dec_obj != NULL )
1528 1529 1530 1531
            {
               [o_controls setupVarMenuItem: o_mi_ffmpeg_pp target:
                    (vlc_object_t *)p_dec_obj var:"ffmpeg-pp-q" selector:
                    @selector(toggleVar:)];
Benjamin Pracht's avatar
Benjamin Pracht committed
1532

1533
                vlc_object_release(p_dec_obj);
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
1534
            }
1535
            vlc_object_release( (vlc_object_t *)p_vout );
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
1536
        }
1537
        vlc_object_release( p_input );
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
1538
    }
1539
    vlc_object_release( p_playlist );
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
1540 1541
}

1542 1543 1544 1545 1546
- (void)refreshVoutDeviceMenu:(NSNotification *)o_notification
{
    int x,y = 0;
    vout_thread_t * p_vout = vlc_object_find( p_intf, VLC_OBJECT_VOUT,
                                              FIND_ANYWHERE );
1547
 
1548 1549
    if(! p_vout )
        return;
1550
 
1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565
    /* clean the menu before adding new entries */
    if( [o_mi_screen hasSubmenu] )
    {
        y = [[o_mi_screen submenu] numberOfItems] - 1;
        msg_Dbg( VLCIntf, "%i items in submenu", y );
        while( x != y )
        {
            msg_Dbg( VLCIntf, "removing item %i of %i", x, y );
            [[o_mi_screen submenu] removeItemAtIndex: x];
            x++;
        }
    }

    [o_controls setupVarMenuItem: o_mi_screen target: (vlc_object_t *)p_vout
                             var: "video-device" selector: @selector(toggleVar:)];
1566
    vlc_object_release( (vlc_object_t *)p_vout );
1567 1568
}

1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579
- (void)setScrollField:(NSString *)o_string stopAfter:(int)timeout
{
    if( timeout != -1 )
        i_end_scroll = mdate() + timeout;
    else
        i_end_scroll = -1;
    [o_scrollfield setStringValue: o_string];
}

- (void)resetScrollField
{
1580
    playlist_t * p_playlist = pl_Yield( p_intf );
1581
    input_thread_t * p_input = p_playlist->p_input;
1582

1583
    i_end_scroll = -1;
1584
    if( p_input && !p_input->b_die )
1585 1586
    {
        NSString *o_temp;
1587
        vlc_object_yield( p_input );
1588 1589 1590 1591 1592 1593
        if( input_item_GetNowPlaying ( p_playlist->status.p_item->p_input ) )
            o_temp = [NSString stringWithUTF8String: 
                input_item_GetNowPlaying ( p_playlist->status.p_item->p_input )];
        else
            o_temp = [NSString stringWithUTF8String:
                p_playlist->status.p_item->p_input->psz_name];
1594
        [self setScrollField: o_temp stopAfter:-1];
1595
        vlc_object_release( p_input );
1596 1597 1598
        vlc_object_release( p_playlist );
        return;
    }
1599
    vlc_object_release( p_playlist );
1600 1601 1602
    [self setScrollField: _NS("VLC media player") stopAfter:-1];
}

1603
- (void)updateMessageArray
1604
{
1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633
    int i_start, i_stop;

    vlc_mutex_lock( p_intf->p_sys->p_sub->p_lock );
    i_stop = *p_intf->p_sys->p_sub->pi_stop;
    vlc_mutex_unlock( p_intf->p_sys->p_sub->p_lock );

    if( p_intf->p_sys->p_sub->i_start != i_stop )
    {
        NSColor *o_white = [NSColor whiteColor];
        NSColor *o_red = [NSColor redColor];
        NSColor *o_yellow = [NSColor yellowColor];
        NSColor *o_gray = [NSColor grayColor];

        NSColor * pp_color[4] = { o_white, o_red, o_yellow, o_gray };
        static const char * ppsz_type[4] = { ": ", " error: ",
                                             " warning: ", " debug: " };

        for( i_start = p_intf->p_sys->p_sub->i_start;
             i_start != i_stop;
             i_start = (i_start+1) % VLC_MSG_QSIZE )
        {
            NSString *o_msg;
            NSDictionary *o_attr;
            NSAttributedString *o_msg_color;

            int i_type = p_intf->p_sys->p_sub->p_msg[i_start].i_type;

            [o_msg_lock lock];

1634
            if( [o_msg_arr count] + 2 > 400 )
1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666
            {
                unsigned rid[] = { 0, 1 };
                [o_msg_arr removeObjectsFromIndices: (unsigned *)&rid
                           numIndices: sizeof(rid)/sizeof(rid[0])];
            }

            o_attr = [NSDictionary dictionaryWithObject: o_gray
                forKey: NSForegroundColorAttributeName];
            o_msg = [NSString stringWithFormat: @"%s%s",
                p_intf->p_sys->p_sub->p_msg[i_start].psz_module,
                ppsz_type[i_type]];
            o_msg_color = [[NSAttributedString alloc]
                initWithString: o_msg attributes: o_attr];
            [o_msg_arr addObject: [o_msg_color autorelease]];

            o_attr = [NSDictionary dictionaryWithObject: pp_color[i_type]
                forKey: NSForegroundColorAttributeName];
            o_msg = [NSString stringWithFormat: @"%s\n",
                p_intf->p_sys->p_sub->p_msg[i_start].psz_msg];
            o_msg_color = [[NSAttributedString alloc]
                initWithString: o_msg attributes: o_attr];
            [o_msg_arr addObject: [o_msg_color autorelease]];

            [o_msg_lock unlock];
        }

        vlc_mutex_lock( p_intf->p_sys->p_sub->p_lock );
        p_intf->p_sys->p_sub->i_start = i_start;
        vlc_mutex_unlock( p_intf->p_sys->p_sub->p_lock );
    }
}

Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
1667
- (void)playStatusUpdated:(int)i_status
1668
{
1669
    if( i_status == PLAYING_S )
1670
    {
1671
        [[[self getControls] getFSPanel] setPause];
1672
        [o_btn_play setImage: o_img_pause];
1673
        [o_btn_play setAlternateImage: o_img_pause_pressed];
1674 1675 1676
        [o_btn_play setToolTip: _NS("Pause")];
        [o_mi_play setTitle: _NS("Pause")];
        [o_dmi_play setTitle: _NS("Pause")];
1677
        [o_vmi_play setTitle: _NS("Pause")];
1678 1679 1680
    }
    else
    {
1681
        [[[self getControls] getFSPanel] setPlay];
1682
        [o_btn_play setImage: o_img_play];
1683
        [o_btn_play setAlternateImage: o_img_play_pressed];
1684 1685 1686
        [o_btn_play setToolTip: _NS("Play")];
        [o_mi_play setTitle: _NS("Play")];
        [o_dmi_play setTitle: _NS("Play")];
1687
        [o_vmi_play setTitle: _NS("Play")];
1688 1689 1690
    }
}

Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
1691 1692 1693 1694 1695 1696
- (void)setSubmenusEnabled:(BOOL)b_enabled
{
    [o_mi_program setEnabled: b_enabled];
    [o_mi_title setEnabled: b_enabled];
    [o_mi_chapter setEnabled: b_enabled];
    [o_mi_audiotrack setEnabled: b_enabled];
1697
    [o_mi_visual setEnabled: b_enabled];
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
1698 1699 1700
    [o_mi_videotrack setEnabled: b_enabled];
    [o_mi_subtitle setEnabled: b_enabled];
    [o_mi_channels setEnabled: b_enabled];
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
1701
    [o_mi_deinterlace setEnabled: b_enabled];
Benjamin Pracht's avatar
Benjamin Pracht committed
1702
    [o_mi_ffmpeg_pp setEnabled: b_enabled];
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
1703 1704
    [o_mi_device setEnabled: b_enabled];
    [o_mi_screen setEnabled: b_enabled];
1705
    [o_mi_aspect_ratio setEnabled: b_enabled];
1706
    [o_mi_crop setEnabled: b_enabled];
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
1707 1708
}

1709 1710 1711
- (void)manageVolumeSlider
{
    audio_volume_t i_volume;
1712
    aout_VolumeGet( p_intf, &i_volume );
1713

1714 1715 1716
    if( i_volume != i_lastShownVolume )
    {
        i_lastShownVolume = i_volume;
1717
        p_intf->p_sys->b_volume_update = TRUE;
1718
    }
1719 1720
}

Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
1721 1722 1723
- (IBAction)timesliderUpdate:(id)sender
{
    float f_updated;
1724 1725
    playlist_t * p_playlist;
    input_thread_t * p_input;
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737

    switch( [[NSApp currentEvent] type] )
    {
        case NSLeftMouseUp:
        case NSLeftMouseDown:
        case NSLeftMouseDragged:
            f_updated = [sender floatValue];
            break;

        default:
            return;
    }
1738 1739
    p_playlist = pl_Yield( p_intf );
    p_input = p_playlist->p_input;
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
1740
    if( p_input != NULL )
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
1741
    {
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
1742
        vlc_value_t time;
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
1743
        vlc_value_t pos;
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
1744
        NSString * o_time;
1745
        char psz_time[MSTRTIME_MAX_SIZE];
1746
        vlc_object_yield( p_input );
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
1747

Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
1748 1749 1750 1751
        pos.f_float = f_updated / 10000.;
        var_Set( p_input, "position", pos );
        [o_timeslider setFloatValue: f_updated];

Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
1752
        var_Get( p_input, "time", &time );
Jérome Decoodt's avatar
Jérome Decoodt committed
1753

1754
        o_time = [NSString stringWithUTF8String: secstotimestr( psz_time, (time.i_time / 1000000) )];
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
1755
        [o_timefield setStringValue: o_time];
1756
        [[[self getControls] getFSPanel] setStreamPos: f_updated andTime: o_time];
1757
        [o_embedded_window setTime: o_time position: f_updated];
1758
        vlc_object_release( p_input );
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
1759
    }
1760
    vlc_object_release( p_playlist );
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
1761 1762
}

1763
- (void)applicationWillTerminate:(NSNotification *)notification
1764 1765
{
    playlist_t * p_playlist;
1766
    vout_thread_t * p_vout;
1767
    int returnedValue = 0;
1768
 
1769
    /* Stop playback */
1770 1771 1772
    p_playlist = pl_Yield( p_intf );
    playlist_Stop( p_playlist );
    vlc_object_release( p_playlist );
1773

1774 1775 1776 1777
    /* make sure that the current volume is saved */
    config_PutInt( p_intf->p_libvlc, "volume", i_lastShownVolume );
    returnedValue = config_SaveConfigFile( p_intf->p_libvlc, "main" );
    if( returnedValue != 0 )
1778
        msg_Err( p_intf,
1779 1780
                 "error while saving volume in osx's terminate method (%i)",
                 returnedValue );
1781

1782
    /* save the prefs if they were changed in the extended panel */
1783
    if(o_extended && [o_extended getConfigChanged])
1784 1785 1786
    {
        [o_extended savePrefs];
    }
1787
 
1788 1789
    p_intf->b_interaction = VLC_FALSE;
    var_DelCallback( p_intf, "interaction", InteractCallback, self );
1790

1791
    /* remove global observer watching for vout device changes correctly */
1792
    [[NSNotificationCenter defaultCenter] removeObserver: self];
1793 1794

    /* release some other objects here, because it isn't sure whether dealloc
1795 1796
     * will be called later on */
    
1797
    if( nib_about_loaded && o_about )
1798
        [o_about release];
1799 1800 1801 1802
    
    if( nib_prefs_loaded && o_prefs )
        [o_prefs release];
    
1803
    if( nib_open_loaded && o_open )
1804
        [o_open release];
1805
 
1806
    if( nib_extended_loaded && o_extended )
1807 1808 1809 1810
    {
        [o_extended collapsAll];
        [o_extended release];
    }
1811
 
1812
    if( nib_bookmarks_loaded && o_bookmarks )
1813 1814
        [o_bookmarks release];

1815 1816 1817
    if( nib_info_loaded && o_info )
        [o_info release];
    
1818
    if( nib_wizard_loaded && o_wizard )
1819
        [o_wizard release];
1820
 
1821 1822 1823 1824 1825
    if( o_embedded_list != nil )
        [o_embedded_list release];

    if( o_interaction_list != nil )
        [o_interaction_list release];
1826

1827 1828 1829
    if( o_eyetv != nil )
        [o_eyetv release];

1830 1831 1832 1833 1834
    if( o_img_pause_pressed != nil )
    {
        [o_img_pause_pressed release];
        o_img_pause_pressed = nil;
    }
Jérome Decoodt's avatar
Jérome Decoodt committed
1835

1836
    if( o_img_play_pressed != nil )
1837 1838 1839 1840
    {
        [o_img_pause_pressed release];
        o_img_pause_pressed = nil;
    }
Jérome Decoodt's avatar
Jérome Decoodt committed
1841

1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853
    if( o_img_pause != nil )
    {
        [o_img_pause release];
        o_img_pause = nil;
    }

    if( o_img_play != nil )
    {
        [o_img_play release];
        o_img_play = nil;
    }

1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866
    if( o_msg_arr != nil )
    {
        [o_msg_arr removeAllObjects];
        [o_msg_arr release];
        o_msg_arr = nil;
    }

    if( o_msg_lock != nil )
    {
        [o_msg_lock release];
        o_msg_lock = nil;
    }

1867 1868
    /* write cached user defaults to disk */
    [[NSUserDefaults standardUserDefaults] synchronize];
Jérome Decoodt's avatar
Jérome Decoodt committed
1869

1870
    vlc_object_kill( p_intf );
1871 1872 1873 1874

    /* Go back to Run() and make libvlc exit properly */
    longjmp( jmpbuffer, 1 );
    /* not reached */
1875
}
Christophe Massiot's avatar
Christophe Massiot committed
1876

1877

1878 1879 1880 1881 1882 1883 1884 1885
- (IBAction)clearRecentItems:(id)sender
{
    [[NSDocumentController sharedDocumentController]
                          clearRecentDocuments: nil];
}

- (void)openRecentItem:(id)sender
{
Jérome Decoodt's avatar
Jérome Decoodt committed
1886
    [self application: nil openFile: [sender title]];
1887 1888
}

1889 1890
- (IBAction)intfOpenFile:(id)sender
{
1891
    if( !nib_open_loaded )
1892 1893 1894 1895 1896 1897 1898
    {
        nib_open_loaded = [NSBundle loadNibNamed:@"Open" owner:self];
        [o_open awakeFromNib];
        [o_open openFile];
    } else {
        [o_open openFile];
    }
1899 1900 1901 1902
}

- (IBAction)intfOpenFileGeneric:(id)sender
{
1903
    if( !nib_open_loaded )
1904 1905 1906 1907 1908 1909 1910
    {
        nib_open_loaded = [NSBundle loadNibNamed:@"Open" owner:self];
        [o_open awakeFromNib];
        [o_open openFileGeneric];
    } else {
        [o_open openFileGeneric];
    }
1911 1912 1913 1914
}

- (IBAction)intfOpenDisc:(id)sender
{
1915
    if( !nib_open_loaded )
1916 1917 1918 1919 1920 1921 1922
    {
        nib_open_loaded = [NSBundle loadNibNamed:@"Open" owner:self];
        [o_open awakeFromNib];
        [o_open openDisc];
    } else {
        [o_open openDisc];
    }
1923 1924 1925 1926
}

- (IBAction)intfOpenNet:(id)sender
{
1927
    if( !nib_open_loaded )
1928 1929 1930 1931 1932 1933 1934
    {
        nib_open_loaded = [NSBundle loadNibNamed:@"Open" owner:self];
        [o_open awakeFromNib];
        [o_open openNet];
    } else {
        [o_open openNet];
    }
1935 1936
}

1937 1938
- (IBAction)showWizard:(id)sender
{
1939
    if( !nib_wizard_loaded )
1940 1941 1942
    {
        nib_wizard_loaded = [NSBundle loadNibNamed:@"Wizard" owner:self];
        [o_wizard initStrings];
1943
        [o_wizard resetWizard];
1944 1945
        [o_wizard showWizard];
    } else {
1946
        [o_wizard resetWizard];
1947 1948 1949 1950
        [o_wizard showWizard];
    }
}

1951 1952
- (IBAction)showExtended:(id)sender
{
1953
    if( o_extended == nil )
1954 1955 1956
    {
        o_extended = [[VLCExtended alloc] init];
    }
1957
    if( !nib_extended_loaded )
1958 1959 1960 1961 1962 1963 1964 1965 1966
    {
        nib_extended_loaded = [NSBundle loadNibNamed:@"Extended" owner:self];
        [o_extended initStrings];
        [o_extended showPanel];
    } else {
        [o_extended showPanel];
    }
}

1967 1968
- (IBAction)showSFilters:(id)sender
{
1969
    if( o_sfilters == nil )
1970 1971 1972
    {
        o_sfilters = [[VLCsFilters alloc] init];
    }
1973
    if( !nib_sfilters_loaded )
1974 1975 1976 1977 1978 1979 1980 1981 1982
    {
        nib_sfilters_loaded = [NSBundle loadNibNamed:@"SFilters" owner:self];
        [o_sfilters initStrings];
        [o_sfilters showAsPanel];
    } else {
        [o_sfilters showAsPanel];
    }
}

1983
- (IBAction)showBookmarks:(id)sender
1984
{
Felix Paul Kühne's avatar
Felix Paul Kühne committed
1985
    /* we need the wizard-nib for the bookmarks's extract functionality */
1986
    if( !nib_wizard_loaded )
Felix Paul Kühne's avatar
Felix Paul Kühne committed
1987 1988
    {
        nib_wizard_loaded = [NSBundle loadNibNamed:@"Wizard" owner:self];
Felix Paul Kühne's avatar
Felix Paul Kühne committed
1989
        [o_wizard initStrings];
Felix Paul Kühne's avatar
Felix Paul Kühne committed
1990
    }
1991
 
1992
    if( !nib_bookmarks_loaded )
1993
        nib_bookmarks_loaded = [NSBundle loadNibNamed:@"Bookmarks" owner:self];
1994 1995

    [o_bookmarks showBookmarks];
1996
}
1997

1998 1999
- (IBAction)viewAbout:(id)sender
{
2000
    if( !nib_about_loaded )
2001
        nib_about_loaded = [NSBundle loadNibNamed:@"About" owner:self];
2002 2003

    [o_about showAbout];
2004 2005
}

2006 2007 2008 2009 2010 2011 2012 2013
- (IBAction)showLicense:(id)sender
{
    if( !nib_about_loaded )
        nib_about_loaded = [NSBundle loadNibNamed:@"About" owner:self];

    [o_about showGPL: sender];
}
    
2014 2015
- (IBAction)viewPreferences:(id)sender
{
2016 2017 2018
    if( !nib_prefs_loaded )
        nib_prefs_loaded = [NSBundle loadNibNamed:@"Preferences" owner: self];

2019 2020 2021 2022 2023 2024 2025
    if( sender == o_mi_sprefs )
    {
        o_sprefs = [[VLCSimplePrefs alloc] init];
        [o_sprefs showSimplePrefs];
    }
    else
        [o_prefs showPrefs];
2026 2027
}

2028
- (IBAction)checkForUpdate:(id)sender
2029
{
2030
#ifdef UPDATE_CHECK
2031
    if( !nib_update_loaded )
Felix Paul Kühne's avatar
Felix Paul Kühne committed
2032
        nib_update_loaded = [NSBundle loadNibNamed:@"Update" owner:self];
2033
    [o_update showUpdateWindow];
2034
#else
2035 2036
    msg_Err( VLCIntf, "Update checker wasn't enabled in this build" );
    intf_UserFatal( VLCIntf, VLC_FALSE, _("Update check failed"), _("Checking for updates was not enabled in this build.") );
2037
#endif
2038
}
Felix Paul Kühne's avatar
Felix Paul Kühne committed
2039

2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050
- (IBAction)viewHelp:(id)sender
{
    if( !nib_about_loaded )
    {
        nib_about_loaded = [NSBundle loadNibNamed:@"About" owner:self];
        [o_about showHelp];
    }
    else
        [o_about showHelp];
}

2051 2052
- (IBAction)openReadMe:(id)sender
{
Jérome Decoodt's avatar
Jérome Decoodt committed
2053 2054
    NSString * o_path = [[NSBundle mainBundle]
        pathForResource: @"README.MacOSX" ofType: @"rtf"];
2055

Jérome Decoodt's avatar
Jérome Decoodt committed
2056
    [[NSWorkspace sharedWorkspace] openFile: o_path
2057
                                   withApplication: @"TextEdit"];
2058 2059
}

2060 2061
- (IBAction)openDocumentation:(id)sender
{
Jérome Decoodt's avatar
Jérome Decoodt committed
2062
    NSURL * o_url = [NSURL URLWithString:
2063 2064 2065 2066 2067
        @"http://www.videolan.org/doc/"];

    [[NSWorkspace sharedWorkspace] openURL: o_url];
}

2068 2069
- (IBAction)openWebsite:(id)sender
{
2070
    NSURL * o_url = [NSURL URLWithString: @"http://www.videolan.org/"];
2071

2072
    [[NSWorkspace sharedWorkspace] openURL: o_url];
2073 2074
}

2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088
- (IBAction)openForum:(id)sender
{
    NSURL * o_url = [NSURL URLWithString: @"http://forum.videolan.org/"];

    [[NSWorkspace sharedWorkspace] openURL: o_url];
}

- (IBAction)openDonate:(id)sender
{
    NSURL * o_url = [NSURL URLWithString: @"http://www.videolan.org/contribute.html#paypal"];

    [[NSWorkspace sharedWorkspace] openURL: o_url];
}

2089 2090
- (IBAction)openCrashLog:(id)sender
{
2091
    NSString * o_path = [@"~/Library/Logs/CrashReporter/VLC.crash.log"
Jérome Decoodt's avatar
Jérome Decoodt committed
2092 2093
                                    stringByExpandingTildeInPath];

2094

2095
    if( [[NSFileManager defaultManager] fileExistsAtPath: o_path ] )
2096
    {
Jérome Decoodt's avatar
Jérome Decoodt committed
2097
        [[NSWorkspace sharedWorkspace] openFile: o_path
2098 2099 2100 2101
                                    withApplication: @"Console"];
    }
    else
    {
2102
        NSBeginInformationalAlertSheet(_NS("No CrashLog found"), _NS("Continue"), nil, nil, o_msgs_panel, self, NULL, NULL, nil, _NS("Couldn't find any trace of a previous crash.") );
2103 2104 2105 2106

    }
}

2107 2108 2109 2110 2111 2112 2113 2114 2115 2116
- (IBAction)viewErrorsAndWarnings:(id)sender
{
    [[[self getInteractionList] getErrorPanel] showPanel];
}

- (IBAction)showMessagesPanel:(id)sender
{
    [o_msgs_panel makeKeyAndOrderFront: sender];
}

2117 2118 2119 2120 2121 2122 2123 2124
- (IBAction)showInformationPanel:(id)sender
{
    if(! nib_info_loaded )
        nib_info_loaded = [NSBundle loadNibNamed:@"MediaInfo" owner: self];
    
    [o_info initPanel];
}

2125 2126 2127 2128 2129 2130 2131
- (void)windowDidBecomeKey:(NSNotification *)o_notification
{
    if( [o_notification object] == o_msgs_panel )
    {
        id o_msg;
        NSEnumerator * o_enum;

Jérome Decoodt's avatar
Jérome Decoodt committed
2132
        [o_messages setString: @""];
2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144

        [o_msg_lock lock];

        o_enum = [o_msg_arr objectEnumerator];

        while( ( o_msg = [o_enum nextObject] ) != nil )
        {
            [o_messages insertText: o_msg];
        }

        [o_msg_lock unlock];
    }
2145 2146
}

2147 2148 2149 2150 2151 2152
- (IBAction)togglePlaylist:(id)sender
{
    NSRect o_rect = [o_window frame];
    /*First, check if the playlist is visible*/
    if( o_rect.size.height <= 200 )
    {
2153 2154
        o_restore_rect = o_rect;
        b_restore_size = true;
2155 2156
        b_small_window = YES; /* we know we are small, make sure this is actually set (see case below) */
        /* make large */
2157
        if( o_size_with_playlist.height > 200 )
2158 2159
        {
            o_rect.size.height = o_size_with_playlist.height;
2160
        } else {
2161 2162
            o_rect.size.height = 500;
        }
2163
 
2164
        if( o_size_with_playlist.width > [o_window minSize].width )
2165
        {
2166 2167
            o_rect.size.width = o_size_with_playlist.width;
        } else {
2168 2169
            o_rect.size.width = 500;
        }
2170
 
2171 2172
        o_rect.size.height = (o_size_with_playlist.height > 200) ?
            o_size_with_playlist.height : 500;
2173 2174 2175
        o_rect.origin.x = [o_window frame].origin.x;
        o_rect.origin.y = [o_window frame].origin.y - o_rect.size.height +
                                                [o_window minSize].height;
2176 2177

        NSRect screenRect = [[o_window screen] visibleFrame];
2178 2179
        if( !NSContainsRect( screenRect, o_rect ) ) {
            if( NSMaxX(o_rect) > NSMaxX(screenRect) )
2180
                o_rect.origin.x = ( NSMaxX(screenRect) - o_rect.size.width );
2181
            if( NSMinY(o_rect) < NSMinY(screenRect) )
2182 2183 2184
                o_rect.origin.y = ( NSMinY(screenRect) );
        }

2185 2186 2187 2188
        [o_btn_playlist setState: YES];
    }
    else
    {
2189
        NSSize curSize = o_rect.size;
2190
        /* make small */
2191
        o_rect.size.height = [o_window minSize].height;
2192
        o_rect.size.width = [o_window minSize].width;
2193 2194 2195 2196
        o_rect.origin.x = [o_window frame].origin.x;
        /* Calculate the position of the lower right corner after resize */
        o_rect.origin.y = [o_window frame].origin.y +
            [o_window frame].size.height - [o_window minSize].height;
2197

2198
        if( b_restore_size )
2199 2200
            o_rect = o_restore_rect;

2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221
        [o_playlist_view setAutoresizesSubviews: NO];
        [o_playlist_view removeFromSuperview];
        [o_btn_playlist setState: NO];
        b_small_window = NO; /* we aren't small here just yet. we are doing an animated resize after this */
    }

    [o_window setFrame: o_rect display:YES animate: YES];
}

- (void)updateTogglePlaylistState
{
    if( [o_window frame].size.height <= 200 )
    {
        [o_btn_playlist setState: NO];
    }
    else
    {
        [o_btn_playlist setState: YES];
    }
}

Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
2222 2223
- (NSSize)windowWillResize:(NSWindow *)sender toSize:(NSSize)proposedFrameSize
{
2224
    /* Not triggered on a window resize or maxification of the window. only by window mouse dragging resize */
2225 2226 2227 2228 2229

   /*Stores the size the controller one resize, to be able to restore it when
     toggling the playlist*/
    o_size_with_playlist = proposedFrameSize;

Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
2230 2231
    if( proposedFrameSize.height <= 200 )
    {
2232
        if( b_small_window == NO )
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
2233
        {
2234 2235 2236 2237
            /* if large and going to small then hide */
            b_small_window = YES;
            [o_playlist_view setAutoresizesSubviews: NO];
            [o_playlist_view removeFromSuperview];
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
2238
        }
2239
        return NSMakeSize( proposedFrameSize.width, [o_window minSize].height);
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
2240
    }
2241 2242 2243
    return proposedFrameSize;
}

2244 2245 2246 2247 2248
- (void)windowDidMove:(NSNotification *)notif
{
    b_restore_size = false;
}

2249 2250 2251
- (void)windowDidResize:(NSNotification *)notif
{
    if( [o_window frame].size.height > 200 && b_small_window )
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
2252
    {
2253 2254
        /* If large and coming from small then show */
        [o_playlist_view setAutoresizesSubviews: YES];
2255
        [o_playlist_view setFrame: NSMakeRect( 10, 10, [o_window frame].size.width - 20, [o_window frame].size.height - [o_window minSize].height - 10 )];
2256 2257 2258
        [o_playlist_view setNeedsDisplay:YES];
        [[o_window contentView] addSubview: o_playlist_view];
        b_small_window = NO;
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
2259
    }
2260
    [self updateTogglePlaylistState];
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
2261 2262
}

2263 2264 2265 2266 2267 2268
@end

@implementation VLCMain (NSMenuValidation)

- (BOOL)validateMenuItem:(NSMenuItem *)o_mi
{
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
2269
    NSString *o_title = [o_mi title];
2270 2271
    BOOL bEnabled = TRUE;

Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
2272 2273
    /* Recent Items Menu */
    if( [o_title isEqualToString: _NS("Clear Menu")] )
2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312
    {
        NSMenu * o_menu = [o_mi_open_recent submenu];
        int i_nb_items = [o_menu numberOfItems];
        NSArray * o_docs = [[NSDocumentController sharedDocumentController]
                                                       recentDocumentURLs];
        UInt32 i_nb_docs = [o_docs count];

        if( i_nb_items > 1 )
        {
            while( --i_nb_items )
            {
                [o_menu removeItemAtIndex: 0];
            }
        }

        if( i_nb_docs > 0 )
        {
            NSURL * o_url;
            NSString * o_doc;

            [o_menu insertItem: [NSMenuItem separatorItem] atIndex: 0];

            while( TRUE )
            {
                i_nb_docs--;

                o_url = [o_docs objectAtIndex: i_nb_docs];

                if( [o_url isFileURL] )
                {
                    o_doc = [o_url path];
                }
                else
                {
                    o_doc = [o_url absoluteString];
                }

                [o_menu insertItemWithTitle: o_doc
                    action: @selector(openRecentItem:)
Jérome Decoodt's avatar
Jérome Decoodt committed
2313
                    keyEquivalent: @"" atIndex: 0];
2314 2315 2316 2317 2318

                if( i_nb_docs == 0 )
                {
                    break;
                }
Jérome Decoodt's avatar
Jérome Decoodt committed
2319
            }
2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334
        }
        else
        {
            bEnabled = FALSE;
        }
    }
    return( bEnabled );
}

@end

@implementation VLCMain (Internal)

- (void)handlePortMessage:(NSPortMessage *)o_msg
{
2335
    id ** val;
2336 2337 2338
    NSData * o_data;
    NSValue * o_value;
    NSInvocation * o_inv;
2339
    NSConditionLock * o_lock;
Jérome Decoodt's avatar
Jérome Decoodt committed
2340

2341
    o_data = [[o_msg components] lastObject];
Jérome Decoodt's avatar
Jérome Decoodt committed
2342
    o_inv = *((NSInvocation **)[o_data bytes]);
2343
    [o_inv getArgument: &o_value atIndex: 2];
2344 2345 2346
    val = (id **)[o_value pointerValue];
    [o_inv setArgument: val[1] atIndex: 2];
    o_lock = *(val[0]);
2347

2348
    [o_lock lock];
2349
    [o_inv invoke];
2350
    [o_lock unlockWithCondition: 1];
2351 2352 2353
}

@end