intf.m 61.6 KB
Newer Older
1
/*****************************************************************************
2
 * intf.m: MacOS X interface module
3
 *****************************************************************************
4
 * Copyright (C) 2002-2005 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 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
 *
 * 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.
 * 
 * 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
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
 *****************************************************************************/

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

#include "intf.h"
#include "vout.h"
36
#include "prefs.h"
37
#include "playlist.h"
38
#include "controls.h"
39
#include "about.h"
40
#include "open.h"
41
#include "wizard.h"
42
#include "extended.h"
43
#include "bookmarks.h"
44
#include "sfilters.h"
45
#include "interaction.h"
46
#include "embeddedwindow.h"
47
/*#include "update.h"*/
48 49 50 51

/*****************************************************************************
 * Local prototypes.
 *****************************************************************************/
52
static void Run ( intf_thread_t *p_intf );
53 54 55 56 57

/*****************************************************************************
 * OpenIntf: initialize interface
 *****************************************************************************/
int E_(OpenIntf) ( vlc_object_t *p_this )
Jérome Decoodt's avatar
Jérome Decoodt committed
58
{
59 60 61 62 63 64 65 66 67
    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
68

69
    p_intf->p_sys->o_pool = [[NSAutoreleasePool alloc] init];
hartman's avatar
hartman committed
70

71 72 73 74 75
    /* Put Cocoa into multithread mode as soon as possible.
     * http://developer.apple.com/techpubs/macosx/Cocoa/
     * TasksAndConcepts/ProgrammingTopics/Multithreading/index.html
     * This thread does absolutely nothing at all. */
    [NSThread detachNewThreadSelector:@selector(self) toTarget:[NSString string] withObject:nil];
Jérome Decoodt's avatar
Jérome Decoodt committed
76

77
    p_intf->p_sys->o_sendport = [[NSPort port] retain];
78
    p_intf->p_sys->p_sub = msg_Subscribe( p_intf, MSG_QUEUE_NORMAL );
hartman's avatar
hartman committed
79
    p_intf->b_play = VLC_TRUE;
80 81 82 83 84 85 86 87 88 89 90
    p_intf->pf_run = Run;

    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
91

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

94 95
    [p_intf->p_sys->o_sendport release];
    [p_intf->p_sys->o_pool release];
Jérome Decoodt's avatar
Jérome Decoodt committed
96

97 98 99 100 101 102 103 104
    free( p_intf->p_sys );
}

/*****************************************************************************
 * Run: main loop
 *****************************************************************************/
static void Run( intf_thread_t *p_intf )
{
105 106 107 108
    /* 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 );
hartman's avatar
-  
hartman committed
109
    [[VLCMain sharedInstance] setIntf: p_intf];
hartman's avatar
hartman committed
110
    [NSBundle loadNibNamed: @"MainMenu" owner: NSApp];
hartman's avatar
-  
hartman committed
111 112
    [NSApp run];
    [[VLCMain sharedInstance] terminate];
113 114
}

115
int ExecuteOnMainThread( id target, SEL sel, void * p_arg )
116
{
117
    int i_ret = 0;
118

hartman's avatar
-  
hartman committed
119
    //NSAutoreleasePool * o_pool = [[NSAutoreleasePool alloc] init];
120 121 122

    if( [target respondsToSelector: @selector(performSelectorOnMainThread:
                                             withObject:waitUntilDone:)] )
123
    {
124 125
        [target performSelectorOnMainThread: sel
                withObject: [NSValue valueWithPointer: p_arg]
hartman's avatar
-  
hartman committed
126
                waitUntilDone: NO];
127
    }
Jérome Decoodt's avatar
Jérome Decoodt committed
128
    else if( NSApp != nil && [[VLCMain sharedInstance] respondsToSelector: @selector(getIntf)] )
129 130 131 132 133 134 135 136 137 138 139 140 141
    {
        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 };

hartman's avatar
hartman committed
142
        p_intf = (intf_thread_t *)VLCIntf;
143 144

        o_recv_port = [[NSPort port] retain];
Jérome Decoodt's avatar
Jérome Decoodt committed
145
        o_v1 = [NSValue valueWithPointer: val];
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
        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
168
    }
169 170 171 172 173
    else
    {
        i_ret = 1;
    }

hartman's avatar
-  
hartman committed
174
    //[o_pool release];
175

176
    return( i_ret );
177 178
}

179 180 181 182
/*****************************************************************************
 * playlistChanged: Callback triggered by the intf-change playlist
 * variable, to let the intf update the playlist.
 *****************************************************************************/
183
static int PlaylistChanged( vlc_object_t *p_this, const char *psz_variable,
184 185
                     vlc_value_t old_val, vlc_value_t new_val, void *param )
{
hartman's avatar
hartman committed
186
    intf_thread_t * p_intf = VLCIntf;
hartman's avatar
hartman committed
187 188
    p_intf->p_sys->b_playlist_update = TRUE;
    p_intf->p_sys->b_intf_update = TRUE;
189
    p_intf->p_sys->b_playmode_update = TRUE;
190 191 192
    return VLC_SUCCESS;
}

bigben's avatar
bigben committed
193 194 195 196
/*****************************************************************************
 * FullscreenChanged: Callback triggered by the fullscreen-change playlist
 * variable, to let the intf update the controller.
 *****************************************************************************/
197
static int FullscreenChanged( vlc_object_t *p_this, const char *psz_variable,
bigben's avatar
bigben committed
198 199 200 201 202 203 204
                     vlc_value_t old_val, vlc_value_t new_val, void *param )
{
    intf_thread_t * p_intf = VLCIntf;
    p_intf->p_sys->b_fullscreen_update = TRUE;
    return VLC_SUCCESS;
}

205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222
/*****************************************************************************
 * 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];
    
    [[NSNotificationCenter defaultCenter] postNotificationName: @"VLCNewInteractionEventNotification" object:[interface getInteractionList]
     userInfo:[NSDictionary dictionaryWithObject:o_value forKey:@"VLCDialogPointer"]];
    
    [o_pool release];
    return VLC_SUCCESS;
}
bigben's avatar
bigben committed
223

224 225 226
static struct
{
    unichar i_nskey;
227
    unsigned int i_vlckey;
Jérome Decoodt's avatar
Jérome Decoodt committed
228
} nskeys_to_vlckeys[] =
229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258
{
    { 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}
};

259
unichar VLCKeyToCocoa( unsigned int i_key )
260
{
261
    unsigned int i;
Jérome Decoodt's avatar
Jérome Decoodt committed
262

263 264 265 266 267 268 269 270 271 272 273 274 275
    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
276

277 278 279 280 281 282 283
    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;
        }
    }
284 285 286 287 288 289 290 291 292 293 294 295 296 297 298
    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;
299 300
}

301
/*****************************************************************************
Jérome Decoodt's avatar
Jérome Decoodt committed
302
 * VLCMain implementation
303 304 305
 *****************************************************************************/
@implementation VLCMain

hartman's avatar
hartman committed
306 307 308 309 310 311 312
static VLCMain *_o_sharedMainInstance = nil;

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

Jérome Decoodt's avatar
Jérome Decoodt committed
313
- (id)init
hartman's avatar
hartman committed
314
{
315
    if( _o_sharedMainInstance) {
hartman's avatar
hartman committed
316 317 318 319
        [self dealloc];
    } else {
        _o_sharedMainInstance = [super init];
    }
320 321
    
    o_about = [[VLAboutBox alloc] init];
322
    o_prefs = nil;
323
    o_open = [[VLCOpen alloc] init];
324
    o_wizard = [[VLCWizard alloc] init];
325
    o_extended = nil;
326
    o_bookmarks = [[VLCBookmarks alloc] init];
327
    o_embedded_list = [[VLCEmbeddedList alloc] init];
328
    o_interaction_list = [[VLCInteractionList alloc] init];
329
    o_sfilters = nil;
330
    /*o_update = [[VLCUpdate alloc] init];*/
331 332

    i_lastShownVolume = -1;
hartman's avatar
hartman committed
333 334 335 336 337 338 339 340 341 342 343
    return _o_sharedMainInstance;
}

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

- (intf_thread_t *)getIntf {
    return p_intf;
}

344 345
- (void)awakeFromNib
{
hartman's avatar
hartman committed
346
    unsigned int i_key = 0;
347
    playlist_t *p_playlist;
348
    vlc_value_t val;
hartman's avatar
hartman committed
349

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

353
    [self initStrings];
hartman's avatar
hartman committed
354
    [o_window setExcludedFromWindowsMenu: TRUE];
355 356
    [o_msgs_panel setExcludedFromWindowsMenu: TRUE];
    [o_msgs_panel setDelegate: self];
Jérome Decoodt's avatar
Jérome Decoodt committed
357

358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378
    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)];
379
    i_key = config_GetInt( p_intf, "key-jump+short" );
380 381
    [o_mi_fwd setKeyEquivalent: [NSString stringWithFormat:@"%C", VLCKeyToCocoa( i_key )]];
    [o_mi_fwd setKeyEquivalentModifierMask: VLCModifiersToCocoa(i_key)];
382
    i_key = config_GetInt( p_intf, "key-jump-short" );
383 384
    [o_mi_bwd setKeyEquivalent: [NSString stringWithFormat:@"%C", VLCKeyToCocoa( i_key )]];
    [o_mi_bwd setKeyEquivalentModifierMask: VLCModifiersToCocoa(i_key)];
385
    i_key = config_GetInt( p_intf, "key-jump+medium" );
386 387
    [o_mi_fwd1m setKeyEquivalent: [NSString stringWithFormat:@"%C", VLCKeyToCocoa( i_key )]];
    [o_mi_fwd1m setKeyEquivalentModifierMask: VLCModifiersToCocoa(i_key)];
388
    i_key = config_GetInt( p_intf, "key-jump-medium" );
389 390
    [o_mi_bwd1m setKeyEquivalent: [NSString stringWithFormat:@"%C", VLCKeyToCocoa( i_key )]];
    [o_mi_bwd1m setKeyEquivalentModifierMask: VLCModifiersToCocoa(i_key)];
391
    i_key = config_GetInt( p_intf, "key-jump+long" );
392 393
    [o_mi_fwd5m setKeyEquivalent: [NSString stringWithFormat:@"%C", VLCKeyToCocoa( i_key )]];
    [o_mi_fwd5m setKeyEquivalentModifierMask: VLCModifiersToCocoa(i_key)];
394
    i_key = config_GetInt( p_intf, "key-jump-long" );
395 396
    [o_mi_bwd5m setKeyEquivalent: [NSString stringWithFormat:@"%C", VLCKeyToCocoa( i_key )]];
    [o_mi_bwd5m setKeyEquivalentModifierMask: VLCModifiersToCocoa(i_key)];
397 398 399 400 401 402
    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)];
hartman's avatar
hartman committed
403 404 405
    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)];
406 407 408
    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)];
409 410 411
    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)];
412

413
    var_Create( p_intf, "intf-change", VLC_VAR_BOOL );
414

415 416
    [self setSubmenusEnabled: FALSE];
    [self manageVolumeSlider];
hartman's avatar
hartman committed
417
    [o_window setDelegate: self];
418 419 420 421
    
    if( [o_window frame].size.height <= 200 )
    {
        b_small_window = YES;
422 423 424
        [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];
425 426 427 428 429 430 431 432 433 434 435
        [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
436

437 438
    o_size_with_playlist = [o_window frame].size;

439
    p_playlist = (playlist_t *) vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
hartman's avatar
hartman committed
440

441 442 443 444
    if( p_playlist )
    {
        /* Check if we need to start playing */
        if( p_intf->b_play )
hartman's avatar
hartman committed
445
        {
446
            playlist_LockControl( p_playlist, PLAYLIST_AUTOPLAY );
hartman's avatar
hartman committed
447
        }
bigben's avatar
bigben committed
448 449 450 451 452
        var_Create( p_playlist, "fullscreen", VLC_VAR_BOOL | VLC_VAR_DOINHERIT);
        val.b_bool = VLC_FALSE;

        var_AddCallback( p_playlist, "fullscreen", FullscreenChanged, self);

453 454
        [o_embedded_window setFullscreen: var_GetBool( p_playlist,
                                                            "fullscreen" )];
455
        vlc_object_release( p_playlist );
hartman's avatar
hartman committed
456
    }
457 458 459 460 461
    
    var_Create( p_intf, "interaction", VLC_VAR_ADDRESS );
    var_AddCallback( p_intf, "interaction", InteractCallback, self );
    p_intf->b_interaction = VLC_TRUE;
    
462
    nib_main_loaded = TRUE;
463 464
}

hartman's avatar
hartman committed
465
- (void)initStrings
466 467
{
    [o_window setTitle: _NS("VLC - Controller")];
468
    [self setScrollField:_NS("VLC media player") stopAfter:-1];
469

Jon Lech Johansen's avatar
Jon Lech Johansen committed
470 471
    /* button controls */
    [o_btn_prev setToolTip: _NS("Previous")];
hartman's avatar
hartman committed
472
    [o_btn_rewind setToolTip: _NS("Rewind")];
Jon Lech Johansen's avatar
Jon Lech Johansen committed
473 474
    [o_btn_play setToolTip: _NS("Play")];
    [o_btn_stop setToolTip: _NS("Stop")];
hartman's avatar
hartman committed
475
    [o_btn_ff setToolTip: _NS("Fast Forward")];
Jon Lech Johansen's avatar
Jon Lech Johansen committed
476
    [o_btn_next setToolTip: _NS("Next")];
hartman's avatar
hartman committed
477
    [o_btn_fullscreen setToolTip: _NS("Fullscreen")];
hartman's avatar
hartman committed
478 479
    [o_volumeslider setToolTip: _NS("Volume")];
    [o_timeslider setToolTip: _NS("Position")];
480
    [o_btn_playlist setToolTip: _NS("Playlist")];
481

Jérome Decoodt's avatar
Jérome Decoodt committed
482
    /* messages panel */
483
    [o_msgs_panel setTitle: _NS("Messages")];
484
    [o_msgs_btn_crashlog setTitle: _NS("Open CrashLog")];
485

Jon Lech Johansen's avatar
Jon Lech Johansen committed
486
    /* main menu */
487 488
    [o_mi_about setTitle: [_NS("About VLC media player") \
        stringByAppendingString: @"..."]];
489
/*    [o_mi_checkForUpdate setTitle: _NS("Check for Update...")];*/
490
    [o_mi_prefs setTitle: _NS("Preferences...")];
hartman's avatar
hartman committed
491 492
    [o_mi_add_intf setTitle: _NS("Add Interface")];
    [o_mu_add_intf setTitle: _NS("Add Interface")];
493
    [o_mi_services setTitle: _NS("Services")];
494
    [o_mi_hide setTitle: _NS("Hide VLC")];
495 496
    [o_mi_hide_others setTitle: _NS("Hide Others")];
    [o_mi_show_all setTitle: _NS("Show All")];
497
    [o_mi_quit setTitle: _NS("Quit VLC")];
498

hartman's avatar
ALL:  
hartman committed
499
    [o_mu_file setTitle: _ANS("1:File")];
hartman's avatar
hartman committed
500 501
    [o_mi_open_generic setTitle: _NS("Open File...")];
    [o_mi_open_file setTitle: _NS("Quick Open File...")];
502 503
    [o_mi_open_disc setTitle: _NS("Open Disc...")];
    [o_mi_open_net setTitle: _NS("Open Network...")];
504 505
    [o_mi_open_recent setTitle: _NS("Open Recent")];
    [o_mi_open_recent_cm setTitle: _NS("Clear Menu")];
506
    [o_mi_open_wizard setTitle: _NS("Streaming/Exporting Wizard...")];
507 508 509 510 511 512 513 514

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

515
    [o_mu_controls setTitle: _NS("Playback")];
516
    [o_mi_play setTitle: _NS("Play")];
517 518 519
    [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
520
    [o_mi_previous setTitle: _NS("Previous")];
521
    [o_mi_next setTitle: _NS("Next")];
522 523 524
    [o_mi_random setTitle: _NS("Random")];
    [o_mi_repeat setTitle: _NS("Repeat One")];
    [o_mi_loop setTitle: _NS("Repeat All")];
525 526
    [o_mi_fwd setTitle: _NS("Step Forward")];
    [o_mi_bwd setTitle: _NS("Step Backward")];
527

hartman's avatar
hartman committed
528
    [o_mi_program setTitle: _NS("Program")];
529
    [o_mu_program setTitle: _NS("Program")];
hartman's avatar
hartman committed
530
    [o_mi_title setTitle: _NS("Title")];
531
    [o_mu_title setTitle: _NS("Title")];
hartman's avatar
hartman committed
532
    [o_mi_chapter setTitle: _NS("Chapter")];
533
    [o_mu_chapter setTitle: _NS("Chapter")];
Jérome Decoodt's avatar
Jérome Decoodt committed
534

hartman's avatar
hartman committed
535
    [o_mu_audio setTitle: _NS("Audio")];
Jon Lech Johansen's avatar
Jon Lech Johansen committed
536 537
    [o_mi_vol_up setTitle: _NS("Volume Up")];
    [o_mi_vol_down setTitle: _NS("Volume Down")];
538
    [o_mi_mute setTitle: _NS("Mute")];
539 540 541 542 543 544
    [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")];
545 546
    [o_mi_visual setTitle: _NS("Visualizations")];
    [o_mu_visual setTitle: _NS("Visualizations")];
Jérome Decoodt's avatar
Jérome Decoodt committed
547

hartman's avatar
hartman committed
548
    [o_mu_video setTitle: _NS("Video")];
549 550 551
    [o_mi_half_window setTitle: _NS("Half Size")];
    [o_mi_normal_window setTitle: _NS("Normal Size")];
    [o_mi_double_window setTitle: _NS("Double Size")];
552
    [o_mi_fittoscreen setTitle: _NS("Fit to Screen")];
553
    [o_mi_fullscreen setTitle: _NS("Fullscreen")];
554
    [o_mi_floatontop setTitle: _NS("Float on Top")];
555
    [o_mi_snapshot setTitle: _NS("Snapshot")];
556 557 558 559 560 561
    [o_mi_videotrack setTitle: _NS("Video Track")];
    [o_mu_videotrack setTitle: _NS("Video Track")];
    [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")];
562
    [o_mi_deinterlace setTitle: _NS("Deinterlace")];
563
    [o_mu_deinterlace setTitle: _NS("Deinterlace")];
bigben's avatar
bigben committed
564 565
    [o_mi_ffmpeg_pp setTitle: _NS("Post processing")];
    [o_mu_ffmpeg_pp setTitle: _NS("Post processing")];
566 567

    [o_mu_window setTitle: _NS("Window")];
568 569
    [o_mi_minimize setTitle: _NS("Minimize Window")];
    [o_mi_close_window setTitle: _NS("Close Window")];
hartman's avatar
hartman committed
570
    [o_mi_controller setTitle: _NS("Controller")];
Jérome Decoodt's avatar
Jérome Decoodt committed
571
    [o_mi_equalizer setTitle: _NS("Equalizer")];
572
    [o_mi_extended setTitle: _NS("Extended Controls")];
573
    [o_mi_bookmarks setTitle: _NS("Bookmarks")];
hartman's avatar
hartman committed
574
    [o_mi_playlist setTitle: _NS("Playlist")];
575
    [o_mi_info setTitle: _NS("Info")];
hartman's avatar
hartman committed
576 577
    [o_mi_messages setTitle: _NS("Messages")];

578 579
    [o_mi_bring_atf setTitle: _NS("Bring All to Front")];

580 581
    [o_mu_help setTitle: _NS("Help")];
    [o_mi_readme setTitle: _NS("ReadMe...")];
hartman's avatar
hartman committed
582
    [o_mi_documentation setTitle: _NS("Online Documentation")];
583
    [o_mi_reportabug setTitle: _NS("Report a Bug")];
584 585
    [o_mi_website setTitle: _NS("VideoLAN Website")];
    [o_mi_license setTitle: _NS("License")];
586 587
    [o_mi_donation setTitle: _NS("Make a donation")];
    [o_mi_forum setTitle: _NS("Online Forum")];
588

589
    /* dock menu */
590
    [o_dmi_play setTitle: _NS("Play")];
591
    [o_dmi_stop setTitle: _NS("Stop")];
592 593
    [o_dmi_next setTitle: _NS("Next")];
    [o_dmi_previous setTitle: _NS("Previous")];
594
    [o_dmi_mute setTitle: _NS("Mute")];
595

596 597
    /* error panel */
    [o_error setTitle: _NS("Error")];
598 599 600 601
    [o_err_lbl setStringValue: _NS("An error has occurred which probably " \
        "prevented the execution of your request:")];
    [o_err_bug_lbl setStringValue: _NS("If you believe that it is a bug, " \
        "please follow the instructions at:")];
602 603
    [o_err_btn_msgs setTitle: _NS("Open Messages Window")];
    [o_err_btn_dismiss setTitle: _NS("Dismiss")];
604
    [o_err_ckbk_surpress setTitle: _NS("Suppress further errors")];
605

606
    [o_info_window setTitle: _NS("Info")];
607 608 609 610
}

- (void)applicationWillFinishLaunching:(NSNotification *)o_notification
{
611 612 613
    o_msg_lock = [[NSLock alloc] init];
    o_msg_arr = [[NSMutableArray arrayWithCapacity: 200] retain];

614
    o_img_play = [[NSImage imageNamed: @"play"] retain];
hartman's avatar
hartman committed
615
    o_img_play_pressed = [[NSImage imageNamed: @"play_blue"] retain];
616
    o_img_pause = [[NSImage imageNamed: @"pause"] retain];
hartman's avatar
hartman committed
617
    o_img_pause_pressed = [[NSImage imageNamed: @"pause_blue"] retain];
618 619

    [p_intf->p_sys->o_sendport setDelegate: self];
Jérome Decoodt's avatar
Jérome Decoodt committed
620
    [[NSRunLoop currentRunLoop]
621 622
        addPort: p_intf->p_sys->o_sendport
        forMode: NSDefaultRunLoopMode];
623

624
    [NSTimer scheduledTimerWithTimeInterval: 0.5
625
        target: self selector: @selector(manageIntf:)
626
        userInfo: nil repeats: FALSE];
627 628 629

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

hartman's avatar
hartman committed
631 632
    [o_controls setupVarMenuItem: o_mi_add_intf target: (vlc_object_t *)p_intf
        var: "intf-add" selector: @selector(toggleVar:)];
633 634

    vlc_thread_set_priority( p_intf, VLC_THREAD_PRIORITY_LOW );
635
}
hartman's avatar
-  
hartman committed
636

637 638
- (BOOL)application:(NSApplication *)o_app openFile:(NSString *)o_filename
{
639
    NSDictionary *o_dic = [NSDictionary dictionaryWithObjectsAndKeys: o_filename, @"ITEM_URL", nil];
640
    [o_playlist appendArray:
641
        [NSArray arrayWithObject: o_dic] atPos: -1 enqueue: NO];
Jérome Decoodt's avatar
Jérome Decoodt committed
642

643 644
    return( TRUE );
}
hartman's avatar
-  
hartman committed
645

hartman's avatar
hartman committed
646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671
- (NSString *)localizedString:(char *)psz
{
    NSString * o_str = nil;

    if( psz != NULL )
    {
        o_str = [[[NSString alloc] initWithUTF8String: psz] autorelease];
    }
    if ( o_str == NULL )
    {
        msg_Err( VLCIntf, "could not translate: %s", psz );
    }

    return( o_str );
}

- (char *)delocalizeString:(NSString *)id
{
    NSData * o_data = [id dataUsingEncoding: NSUTF8StringEncoding
                          allowLossyConversion: NO];
    char * psz_string;

    if ( o_data == nil )
    {
        o_data = [id dataUsingEncoding: NSUTF8StringEncoding
                     allowLossyConversion: YES];
Jérome Decoodt's avatar
Jérome Decoodt committed
672
        psz_string = malloc( [o_data length] + 1 );
hartman's avatar
hartman committed
673 674 675 676 677 678 679
        [o_data getBytes: psz_string];
        psz_string[ [o_data length] ] = '\0';
        msg_Err( VLCIntf, "cannot convert to wanted encoding: %s",
                 psz_string );
    }
    else
    {
Jérome Decoodt's avatar
Jérome Decoodt committed
680
        psz_string = malloc( [o_data length] + 1 );
hartman's avatar
hartman committed
681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702
        [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
703

hartman's avatar
hartman committed
704 705 706 707
    [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
708

hartman's avatar
hartman committed
709 710
    o_wrapped = [o_in_string mutableCopy];
    glyphRange = [o_layout_manager glyphRangeForTextContainer: o_container];
Jérome Decoodt's avatar
Jérome Decoodt committed
711

hartman's avatar
hartman committed
712 713 714 715 716 717 718 719 720 721 722 723 724 725 726
    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];
        if ([o_wrapped lineRangeForRange:
                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
727

hartman's avatar
hartman committed
728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745
    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;
hartman's avatar
-  
hartman committed
746
    p_hotkeys = p_intf->p_vlc->p_hotkeys;
hartman's avatar
hartman committed
747 748 749 750 751 752 753 754 755 756 757 758 759 760

    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];

761 762 763 764 765 766
    switch( key )
    {
        case NSDeleteCharacter:
        case NSDeleteFunctionKey:
        case NSDeleteCharFunctionKey:
        case NSBackspaceCharacter:
767 768 769 770 771 772 773
        case NSUpArrowFunctionKey:
        case NSDownArrowFunctionKey:
        case NSRightArrowFunctionKey:
        case NSLeftArrowFunctionKey:
        case NSEnterCharacter:
        case NSCarriageReturnCharacter:
            return NO;
774 775
    }

hartman's avatar
hartman committed
776 777 778 779 780 781
    val.i_int |= CocoaKeyToVLC( key );

    for( i = 0; p_hotkeys[i].psz_action != NULL; i++ )
    {
        if( p_hotkeys[i].i_key == val.i_int )
        {
hartman's avatar
-  
hartman committed
782
            var_Set( p_intf->p_vlc, "key-pressed", val );
hartman's avatar
hartman committed
783 784 785 786 787 788
            return YES;
        }
    }

    return NO;
}
789

hartman's avatar
hartman committed
790 791 792 793 794 795 796 797 798
- (id)getControls
{
    if ( o_controls )
    {
        return o_controls;
    }
    return nil;
}

hartman's avatar
hartman committed
799 800 801 802 803 804 805 806 807
- (id)getPlaylist
{
    if ( o_playlist )
    {
        return o_playlist;
    }
    return nil;
}

808 809 810 811 812 813
- (id)getInfo
{
    if ( o_info )
    {
        return o_info;
    }
814 815 816 817 818 819 820 821 822 823
    return nil;
}

- (id)getWizard
{
    if ( o_wizard )
    {
        return o_wizard;
    }
    return nil;
824 825
}

826 827 828 829 830 831 832 833 834
- (id)getBookmarks
{
    if ( o_bookmarks )
    {
        return o_bookmarks;
    }
    return nil;
}

835 836 837 838 839 840 841 842 843
- (id)getEmbeddedList
{
    if( o_embedded_list )
    {
        return o_embedded_list;
    }
    return nil;
}

844 845 846 847 848 849 850 851 852
- (id)getInteractionList
{
    if( o_interaction_list )
    {
        return o_interaction_list;
    }
    return nil;
}

853 854
- (void)manage
{
hartman's avatar
hartman committed
855
    playlist_t * p_playlist;
Jérome Decoodt's avatar
Jérome Decoodt committed
856

hartman's avatar
-  
hartman committed
857
    /* new thread requires a new pool */
858 859
    NSAutoreleasePool * o_pool = [[NSAutoreleasePool alloc] init];

860 861
    vlc_thread_set_priority( p_intf, VLC_THREAD_PRIORITY_LOW );

Jérome Decoodt's avatar
Jérome Decoodt committed
862
    p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
hartman's avatar
hartman committed
863 864 865 866 867 868
                                              FIND_ANYWHERE );

    if( p_playlist != NULL )
    {
        var_AddCallback( p_playlist, "intf-change", PlaylistChanged, self );
        var_AddCallback( p_playlist, "item-change", PlaylistChanged, self );
869 870
        var_AddCallback( p_playlist, "item-append", PlaylistChanged, self );
        var_AddCallback( p_playlist, "item-deleted", PlaylistChanged, self );
hartman's avatar
hartman committed
871
        var_AddCallback( p_playlist, "playlist-current", PlaylistChanged, self );
bigben's avatar
bigben committed
872

hartman's avatar
hartman committed
873 874 875
        vlc_object_release( p_playlist );
    }

876 877 878 879
    while( !p_intf->b_die )
    {
        vlc_mutex_lock( &p_intf->change_lock );

hartman's avatar
hartman committed
880
#define p_input p_intf->p_sys->p_input
Jérome Decoodt's avatar
Jérome Decoodt committed
881

hartman's avatar
hartman committed
882 883 884 885
        if( p_input == NULL )
        {
            p_input = (input_thread_t *)vlc_object_find( p_intf, VLC_OBJECT_INPUT,
                                           FIND_ANYWHERE );
Jérome Decoodt's avatar
Jérome Decoodt committed
886

hartman's avatar
hartman committed
887 888
            /* Refresh the interface */
            if( p_input )
889
            {
hartman's avatar
hartman committed
890
                msg_Dbg( p_intf, "input has changed, refreshing interface" );
hartman's avatar
hartman committed
891
                p_intf->p_sys->b_input_update = VLC_TRUE;
892
            }
893
        }
hartman's avatar
hartman committed
894
        else if( p_input->b_die || p_input->b_dead )
hartman's avatar
hartman committed
895 896
        {
            /* input stopped */
hartman's avatar
hartman committed
897 898
            p_intf->p_sys->b_intf_update = VLC_TRUE;
            p_intf->p_sys->i_play_status = END_S;
899
            [self setScrollField: _NS("VLC media player") stopAfter:-1];
hartman's avatar
hartman committed
900 901 902 903
            vlc_object_release( p_input );
            p_input = NULL;
        }
#undef p_input
904

905 906 907
        /* Manage volume status */
        [self manageVolumeSlider];

908
        vlc_mutex_unlock( &p_intf->change_lock );
909
        msleep( 100000 );
910 911 912 913 914 915
    }
    [o_pool release];
}

- (void)manageIntf:(NSTimer *)o_timer
{
hartman's avatar
hartman committed
916 917
    vlc_value_t val;

918 919 920 921 922
    if( p_intf->p_vlc->b_die == VLC_TRUE )
    {
        [o_timer invalidate];
        return;
    }
923

hartman's avatar
hartman committed
924
#define p_input p_intf->p_sys->p_input
hartman's avatar
hartman committed
925 926 927 928 929 930 931
    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;
    }
932 933 934 935 936 937 938 939
    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;

hartman's avatar
hartman committed
940 941
        playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
                                                   FIND_ANYWHERE );
942
        b_plmul = p_playlist->i_size > 1;
Jérome Decoodt's avatar
Jérome Decoodt committed
943