intf.m 90.8 KB
Newer Older
1
/*****************************************************************************
2
 * intf.m: MacOS X interface module
3
 *****************************************************************************
4
 * Copyright (C) 2002-2009 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
dionoea's avatar
dionoea 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>
hartman's avatar
hartman committed
33
#include <vlc_common.h>
34
#include <vlc_keys.h>
35
#include <vlc_dialog.h>
36
#include <unistd.h> /* execl() */
37

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

58
#import <AddressBook/AddressBook.h>
59

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

65
static void * ManageThread( void *user_data );
66

67
68
static unichar VLCKeyToCocoa( unsigned int i_key );
static unsigned int VLCModifiersToCocoa( unsigned int i_key );
69

70
#pragma mark -
71
#pragma mark VLC Interface Object Callbacks
72

73
74
75
/*****************************************************************************
 * OpenIntf: initialize interface
 *****************************************************************************/
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
76
int OpenIntf ( vlc_object_t *p_this )
Jérome Decoodt's avatar
Jérome Decoodt committed
77
{
78
79
80
81
    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 )
Jean-Paul Saman's avatar
Jean-Paul Saman committed
82
        return VLC_ENOMEM;
83
84

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

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

88
89
    /* subscribe to LibVLCCore's messages */
    p_intf->p_sys->p_sub = msg_Subscribe( p_intf->p_libvlc, MsgCallback, NULL );
90
    p_intf->pf_run = Run;
91
    p_intf->b_should_run_on_first_thread = true;
92

Jean-Paul Saman's avatar
Jean-Paul Saman committed
93
    return VLC_SUCCESS;
94
95
96
97
98
}

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

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

105
106
107
108
109
110
    free( p_intf->p_sys );
}

/*****************************************************************************
 * Run: main loop
 *****************************************************************************/
111
112
jmp_buf jmpbuffer;

113
114
static void Run( intf_thread_t *p_intf )
{
115
116
    sigset_t set;

117
118
119
120
    /* 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 );
121
122
123
124
125
126
127
128
129

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

130
131
132
133
    NSAutoreleasePool * o_pool = [[NSAutoreleasePool alloc] init];

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

hartman's avatar
-    
hartman committed
136
    [[VLCMain sharedInstance] setIntf: p_intf];
hartman's avatar
hartman committed
137
    [NSBundle loadNibNamed: @"MainMenu" owner: NSApp];
138
139
140
141
142

    /* Install a jmpbuffer to where we can go back before the NSApp exit
     * see applicationWillTerminate: */
    if(setjmp(jmpbuffer) == 0)
        [NSApp run];
143
    
144
    [o_pool release];
145
146
}

147
148
#pragma mark -
#pragma mark Variables Callback
149

150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
/*****************************************************************************
 * MsgCallback: Callback triggered by the core once a new debug message is
 * ready to be displayed. We store everything in a NSArray in our Cocoa part
 * of this file, so we are forwarding everything through notifications.
 *****************************************************************************/
static void MsgCallback( msg_cb_data_t *data, msg_item_t *item, unsigned int i )
{
    int canc = vlc_savecancel();
    NSAutoreleasePool * o_pool = [[NSAutoreleasePool alloc] init];
    
    NSDictionary *o_dict = [NSDictionary dictionaryWithObjects: 
                            [NSArray arrayWithObjects: 
                             [NSString stringWithUTF8String: item->psz_module],
                             [NSString stringWithUTF8String: item->psz_msg],
                             [NSNumber numberWithInt: item->i_type], nil] 
                                                       forKeys:
                            [NSArray arrayWithObjects: @"Module", @"Message", @"Type", nil]];
    
    [[NSNotificationCenter defaultCenter] postNotificationName: @"VLCCoreMessageReceived" 
                                                        object: nil 
                                                      userInfo: o_dict];
    
    [o_pool release];
    vlc_restorecancel( canc );
}


177
178
179
180
/*****************************************************************************
 * playlistChanged: Callback triggered by the intf-change playlist
 * variable, to let the intf update the playlist.
 *****************************************************************************/
181
static int PlaylistChanged( vlc_object_t *p_this, const char *psz_variable,
182
183
                     vlc_value_t old_val, vlc_value_t new_val, void *param )
{
hartman's avatar
hartman committed
184
    intf_thread_t * p_intf = VLCIntf;
Jean-Paul Saman's avatar
Jean-Paul Saman committed
185
186
187
188
189
190
191
    if( p_intf && p_intf->p_sys )
    {
        p_intf->p_sys->b_intf_update = true;
        p_intf->p_sys->b_playlist_update = true;
        p_intf->p_sys->b_playmode_update = true;
        p_intf->p_sys->b_current_title_update = true;
    }
192
193
194
195
196
197
198
199
200
201
202
203
    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;
Jean-Paul Saman's avatar
Jean-Paul Saman committed
204
205
    if( p_intf && p_intf->p_sys )
        p_intf->p_sys->b_intf_show = true;
206
207
208
    return VLC_SUCCESS;
}

bigben's avatar
bigben committed
209
210
211
212
/*****************************************************************************
 * FullscreenChanged: Callback triggered by the fullscreen-change playlist
 * variable, to let the intf update the controller.
 *****************************************************************************/
213
static int FullscreenChanged( vlc_object_t *p_this, const char *psz_variable,
bigben's avatar
bigben committed
214
215
216
                     vlc_value_t old_val, vlc_value_t new_val, void *param )
{
    intf_thread_t * p_intf = VLCIntf;
Jean-Paul Saman's avatar
Jean-Paul Saman committed
217
218
    if( p_intf && p_intf->p_sys )
        p_intf->p_sys->b_fullscreen_update = true;
bigben's avatar
bigben committed
219
220
221
    return VLC_SUCCESS;
}

222
223
224
225
226
227
228
229
230
231
232
/*****************************************************************************
 * 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];
233
 
234
235
    [[NSNotificationCenter defaultCenter] postNotificationName: @"VLCNewInteractionEventNotification" object:[interface getInteractionList]
     userInfo:[NSDictionary dictionaryWithObject:o_value forKey:@"VLCDialogPointer"]];
236
 
237
238
239
    [o_pool release];
    return VLC_SUCCESS;
}
bigben's avatar
bigben committed
240

241
#pragma mark -
242
243
244
245
246
#pragma mark Private

@interface VLCMain ()
- (void)_removeOldPreferences;
@end
247

248
/*****************************************************************************
Jérome Decoodt's avatar
Jérome Decoodt committed
249
 * VLCMain implementation
250
251
252
 *****************************************************************************/
@implementation VLCMain

253
254
255
#pragma mark -
#pragma mark Initialization

hartman's avatar
hartman committed
256
257
258
259
260
261
262
static VLCMain *_o_sharedMainInstance = nil;

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

Jérome Decoodt's avatar
Jérome Decoodt committed
263
- (id)init
hartman's avatar
hartman committed
264
{
265
266
    if( _o_sharedMainInstance) 
    {
hartman's avatar
hartman committed
267
        [self dealloc];
268
269
270
        return _o_sharedMainInstance;
    } 
    else
hartman's avatar
hartman committed
271
        _o_sharedMainInstance = [super init];
272

273
274
275
276
277
    o_msg_lock = [[NSLock alloc] init];
    o_msg_arr = [[NSMutableArray arrayWithCapacity: 200] retain];
    /* subscribe to LibVLC's debug messages as early as possible (for us) */
    [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(libvlcMessageReceived:) name: @"VLCCoreMessageReceived" object: nil];
    
278
    o_about = [[VLAboutBox alloc] init];
279
    o_prefs = nil;
280
    o_open = [[VLCOpen alloc] init];
281
    o_wizard = [[VLCWizard alloc] init];
282
    o_vlm = [[VLCVLMController alloc] init];
283
    o_extended = nil;
284
    o_bookmarks = [[VLCBookmarks alloc] init];
285
    o_embedded_list = [[VLCEmbeddedList alloc] init];
286
    o_interaction_list = [[VLCInteractionList alloc] init];
287
    o_info = [[VLCInfo alloc] init];
288
#ifdef UPDATE_CHECK
Rafaël Carré's avatar
Rafaël Carré committed
289
    o_update = [[VLCUpdate alloc] init];
290
#endif
291
292

    i_lastShownVolume = -1;
293
294

    o_remote = [[AppleRemote alloc] init];
295
    [o_remote setClickCountEnabledButtons: kRemoteButtonPlay];
296
    [o_remote setDelegate: _o_sharedMainInstance];
297

298
299
300
301
302
303
304
305
    o_eyetv = [[VLCEyeTVController alloc] init];

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

hartman's avatar
hartman committed
306
307
308
309
310
311
312
313
314
315
316
    return _o_sharedMainInstance;
}

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

- (intf_thread_t *)getIntf {
    return p_intf;
}

317
318
- (void)awakeFromNib
{
hartman's avatar
hartman committed
319
    unsigned int i_key = 0;
320
    playlist_t *p_playlist;
321
    vlc_value_t val;
hartman's avatar
hartman committed
322

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

326
327
328
329
330
331
    /* check whether the user runs a valid version of OS X */
    if( MACOS_VERSION < 10.5f )
    {
        NSAlert *ourAlert;
        int i_returnValue;
        NSString *o_blabla;
332
        if( MACOS_VERSION == 10.4f )
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
            o_blabla = _NS("VLC's last release for your OS is the 0.9 series." );
        else if( MACOS_VERSION == 10.3f )
            o_blabla = _NS("VLC's last release for your OS is VLC 0.8.6i, which is prone to known security issues." );
        else // 10.2 and 10.1, still 3% of the OS X market share
            o_blabla = _NS("VLC's last release for your OS is VLC 0.7.2, which is highly out of date and prone to " \
                         "known security issues. We recommend you to update your Mac to a modern version of Mac OS X.");
        ourAlert = [NSAlert alertWithMessageText: _NS("Your version of Mac OS X is no longer supported")
                                   defaultButton: _NS("Quit")
                                 alternateButton: NULL
                                     otherButton: NULL
                       informativeTextWithFormat: _NS("VLC media player %s requires Mac OS X 10.5 or higher.\n\n%@"), VLC_Version(), o_blabla];
        [ourAlert setAlertStyle: NSCriticalAlertStyle];
        i_returnValue = [ourAlert runModal];
        [NSApp performSelectorOnMainThread: @selector(terminate:) withObject:nil waitUntilDone:NO];
        return;
    }

350
    [self initStrings];
351
352
353

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

356
357
358
359
360
361
362
363
364
    /* In code and not in Nib for 10.4 compat */
    NSToolbar * toolbar = [[[NSToolbar alloc] initWithIdentifier:@"mainControllerToolbar"] autorelease];
    [toolbar setDelegate:self];
    [toolbar setShowsBaselineSeparator:NO];
    [toolbar setAllowsUserCustomization:NO];
    [toolbar setDisplayMode:NSToolbarDisplayModeIconOnly];
    [toolbar setAutosavesConfiguration:YES];
    [o_window setToolbar:toolbar];

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

420
    var_Create( p_intf, "intf-change", VLC_VAR_BOOL );
421

422
    [self setSubmenusEnabled: FALSE];
423
    [o_volumeslider setEnabled: YES];
424
    [self manageVolumeSlider];
hartman's avatar
hartman committed
425
    [o_window setDelegate: self];
426
 
427
    b_restore_size = false;
428
429
430
431
432

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

    if( [o_window contentRectForFrameRect:[o_window frame]].size.height <= 169. )
433
434
    {
        b_small_window = YES;
435
436
437
        [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];
438
439
440
441
442
        [o_playlist_view setAutoresizesSubviews: NO];
    }
    else
    {
        b_small_window = NO;
443
444
        NSRect contentRect = [o_window contentRectForFrameRect:[o_window frame]];
        [o_playlist_view setFrame: NSMakeRect( 0, 0, contentRect.size.width, contentRect.size.height - [o_window contentMinSize].height )];
445
446
447
448
        [o_playlist_view setNeedsDisplay:YES];
        [o_playlist_view setAutoresizesSubviews: YES];
        [[o_window contentView] addSubview: o_playlist_view];
    }
449

450
    [self updateTogglePlaylistState];
Jérome Decoodt's avatar
Jérome Decoodt committed
451

452
    o_size_with_playlist = [o_window contentRectForFrameRect:[o_window frame]].size;
453

dionoea's avatar
dionoea committed
454
    p_playlist = pl_Hold( p_intf );
hartman's avatar
hartman committed
455

456
    var_Create( p_playlist, "fullscreen", VLC_VAR_BOOL | VLC_VAR_DOINHERIT);
457
    val.b_bool = false;
bigben's avatar
bigben committed
458

459
    var_AddCallback( p_playlist, "fullscreen", FullscreenChanged, self);
460
    var_AddCallback( p_intf->p_libvlc, "intf-show", ShowController, self);
bigben's avatar
bigben committed
461

462
    pl_Release( p_intf );
463
 
464
465
    var_Create( p_intf, "interaction", VLC_VAR_ADDRESS );
    var_AddCallback( p_intf, "interaction", InteractCallback, self );
466
    interaction_Register( p_intf );
467

468
    /* update the playmode stuff */
469
    p_intf->p_sys->b_playmode_update = true;
470

471
472
473
474
    [[NSNotificationCenter defaultCenter] addObserver: self
                                             selector: @selector(refreshVoutDeviceMenu:)
                                                 name: NSApplicationDidChangeScreenParametersNotification
                                               object: nil];
475
476
477
478
479
480
481
482
483
484
485

    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];
    
486
    nib_main_loaded = TRUE;
487
488
}

489
- (void)applicationWillFinishLaunching:(NSNotification *)o_notification
490
{
491
492
493
494
    /* FIXME: don't poll */
    interfaceTimer = [[NSTimer scheduledTimerWithTimeInterval: 0.5
                                     target: self selector: @selector(manageIntf:)
                                   userInfo: nil repeats: FALSE] retain];
495

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

499
500
    [o_controls setupVarMenuItem: o_mi_add_intf target: (vlc_object_t *)p_intf
        var: "intf-add" selector: @selector(toggleVar:)];
501

502
503
    vlc_thread_set_priority( p_intf, VLC_THREAD_PRIORITY_LOW );
}
504

505
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
506
{
507
508
    [self _removeOldPreferences];

509
510
511
#ifdef UPDATE_CHECK
    /* Check for update silently on startup */
    if( !nib_update_loaded )
Felix Paul Kühne's avatar
Felix Paul Kühne committed
512
        nib_update_loaded = [NSBundle loadNibNamed:@"Update" owner: NSApp];
513
514
515
516
517
518
519
520
521
522

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

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

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

hartman's avatar
hartman committed
525
- (void)initStrings
526
{
Felix Paul Kühne's avatar
Felix Paul Kühne committed
527
    [o_window setTitle: _NS("VLC media player")];
528
    [self setScrollField:_NS("VLC media player") stopAfter:-1];
529

Jon Lech Johansen's avatar
Jon Lech Johansen committed
530
531
    /* button controls */
    [o_btn_prev setToolTip: _NS("Previous")];
hartman's avatar
hartman committed
532
    [o_btn_rewind setToolTip: _NS("Rewind")];
Jon Lech Johansen's avatar
Jon Lech Johansen committed
533
534
    [o_btn_play setToolTip: _NS("Play")];
    [o_btn_stop setToolTip: _NS("Stop")];
hartman's avatar
hartman committed
535
    [o_btn_ff setToolTip: _NS("Fast Forward")];
Jon Lech Johansen's avatar
Jon Lech Johansen committed
536
    [o_btn_next setToolTip: _NS("Next")];
hartman's avatar
hartman committed
537
    [o_btn_fullscreen setToolTip: _NS("Fullscreen")];
hartman's avatar
hartman committed
538
539
    [o_volumeslider setToolTip: _NS("Volume")];
    [o_timeslider setToolTip: _NS("Position")];
540
    [o_btn_playlist setToolTip: _NS("Playlist")];
541

Jérome Decoodt's avatar
Jérome Decoodt committed
542
    /* messages panel */
543
    [o_msgs_panel setTitle: _NS("Messages")];
544
545
    [o_msgs_crashlog_btn setTitle: _NS("Open CrashLog...")];
    [o_msgs_save_btn setTitle: _NS("Save this Log...")];
546

Jon Lech Johansen's avatar
Jon Lech Johansen committed
547
    /* main menu */
548
549
    [o_mi_about setTitle: [_NS("About VLC media player") \
        stringByAppendingString: @"..."]];
550
    [o_mi_checkForUpdate setTitle: _NS("Check for Update...")];
551
    [o_mi_prefs setTitle: _NS("Preferences...")];
hartman's avatar
hartman committed
552
553
    [o_mi_add_intf setTitle: _NS("Add Interface")];
    [o_mu_add_intf setTitle: _NS("Add Interface")];
554
    [o_mi_services setTitle: _NS("Services")];
555
    [o_mi_hide setTitle: _NS("Hide VLC")];
556
557
    [o_mi_hide_others setTitle: _NS("Hide Others")];
    [o_mi_show_all setTitle: _NS("Show All")];
558
    [o_mi_quit setTitle: _NS("Quit VLC")];
559

hartman's avatar
ALL:    
hartman committed
560
    [o_mu_file setTitle: _ANS("1:File")];
561
562
    [o_mi_open_generic setTitle: _NS("Advanced Open File...")];
    [o_mi_open_file setTitle: _NS("Open File...")];
563
564
    [o_mi_open_disc setTitle: _NS("Open Disc...")];
    [o_mi_open_net setTitle: _NS("Open Network...")];
565
    [o_mi_open_capture setTitle: _NS("Open Capture Device...")];
566
567
    [o_mi_open_recent setTitle: _NS("Open Recent")];
    [o_mi_open_recent_cm setTitle: _NS("Clear Menu")];
568
    [o_mi_open_wizard setTitle: _NS("Streaming/Exporting Wizard...")];
569
570
571
572
573
574
575
576

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

577
    [o_mu_controls setTitle: _NS("Playback")];
578
    [o_mi_play setTitle: _NS("Play")];
579
580
581
    [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
582
    [o_mi_previous setTitle: _NS("Previous")];
583
    [o_mi_next setTitle: _NS("Next")];
584
585
586
    [o_mi_random setTitle: _NS("Random")];
    [o_mi_repeat setTitle: _NS("Repeat One")];
    [o_mi_loop setTitle: _NS("Repeat All")];
587
588
    [o_mi_fwd setTitle: _NS("Step Forward")];
    [o_mi_bwd setTitle: _NS("Step Backward")];
589

hartman's avatar
hartman committed
590
    [o_mi_program setTitle: _NS("Program")];
591
    [o_mu_program setTitle: _NS("Program")];
hartman's avatar
hartman committed
592
    [o_mi_title setTitle: _NS("Title")];
593
    [o_mu_title setTitle: _NS("Title")];
hartman's avatar
hartman committed
594
    [o_mi_chapter setTitle: _NS("Chapter")];
595
    [o_mu_chapter setTitle: _NS("Chapter")];
Jérome Decoodt's avatar
Jérome Decoodt committed
596

hartman's avatar
hartman committed
597
    [o_mu_audio setTitle: _NS("Audio")];
598
599
    [o_mi_vol_up setTitle: _NS("Increase Volume")];
    [o_mi_vol_down setTitle: _NS("Decrease Volume")];
600
    [o_mi_mute setTitle: _NS("Mute")];
601
602
603
604
605
606
    [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")];
607
608
    [o_mi_visual setTitle: _NS("Visualizations")];
    [o_mu_visual setTitle: _NS("Visualizations")];
Jérome Decoodt's avatar
Jérome Decoodt committed
609

hartman's avatar
hartman committed
610
    [o_mu_video setTitle: _NS("Video")];
611
612
613
    [o_mi_half_window setTitle: _NS("Half Size")];
    [o_mi_normal_window setTitle: _NS("Normal Size")];
    [o_mi_double_window setTitle: _NS("Double Size")];
614
    [o_mi_fittoscreen setTitle: _NS("Fit to Screen")];
615
    [o_mi_fullscreen setTitle: _NS("Fullscreen")];
616
    [o_mi_floatontop setTitle: _NS("Float on Top")];
617
    [o_mi_snapshot setTitle: _NS("Snapshot")];
618
619
    [o_mi_videotrack setTitle: _NS("Video Track")];
    [o_mu_videotrack setTitle: _NS("Video Track")];
620
621
    [o_mi_aspect_ratio setTitle: _NS("Aspect-ratio")];
    [o_mu_aspect_ratio setTitle: _NS("Aspect-ratio")];
bigben's avatar
bigben committed
622
623
    [o_mi_crop setTitle: _NS("Crop")];
    [o_mu_crop setTitle: _NS("Crop")];
624
625
    [o_mi_screen setTitle: _NS("Fullscreen Video Device")];
    [o_mu_screen setTitle: _NS("Fullscreen Video Device")];
626
627
    [o_mi_subtitle setTitle: _NS("Subtitles Track")];
    [o_mu_subtitle setTitle: _NS("Subtitles Track")];
628
    [o_mi_addSub setTitle: _NS("Open File...")];
629
    [o_mi_deinterlace setTitle: _NS("Deinterlace")];
630
    [o_mu_deinterlace setTitle: _NS("Deinterlace")];
bigben's avatar
bigben committed
631
632
    [o_mi_ffmpeg_pp setTitle: _NS("Post processing")];
    [o_mu_ffmpeg_pp setTitle: _NS("Post processing")];
hartman's avatar
hartman committed
633
634
635
636
637
638
639
    [o_mi_teletext setTitle: _NS("Teletext")];
    [o_mi_teletext_transparent setTitle: _NS("Transparent")];
    [o_mi_teletext_index setTitle: _NS("Index")];
    [o_mi_teletext_red setTitle: _NS("Red")];
    [o_mi_teletext_green setTitle: _NS("Green")];
    [o_mi_teletext_yellow setTitle: _NS("Yellow")];
    [o_mi_teletext_blue setTitle: _NS("Blue")];
640
641

    [o_mu_window setTitle: _NS("Window")];
642
643
    [o_mi_minimize setTitle: _NS("Minimize Window")];
    [o_mi_close_window setTitle: _NS("Close Window")];
644
645
646
647
648
649
650
651
    [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...")];
hartman's avatar
hartman committed
652

653
654
    [o_mi_bring_atf setTitle: _NS("Bring All to Front")];

655
    [o_mu_help setTitle: _NS("Help")];
656
    [o_mi_help setTitle: _NS("VLC media player Help...")];
657
    [o_mi_readme setTitle: _NS("ReadMe / FAQ...")];
658
    [o_mi_license setTitle: _NS("License")];
659
660
661
662
    [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...")];
663

664
    /* dock menu */
665
    [o_dmi_play setTitle: _NS("Play")];
666
    [o_dmi_stop setTitle: _NS("Stop")];
667
668
    [o_dmi_next setTitle: _NS("Next")];
    [o_dmi_previous setTitle: _NS("Previous")];
669
    [o_dmi_mute setTitle: _NS("Mute")];
670
 
671
672
673
674
675
676
677
678
679
680
    /* 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")];
681
682
683
684
685
686
687

    /* crash reporter panel */
    [o_crashrep_send_btn setTitle: _NS("Send")];
    [o_crashrep_dontSend_btn setTitle: _NS("Don't Send")];
    [o_crashrep_title_txt setStringValue: _NS("VLC crashed previously")];
    [o_crashrep_win setTitle: _NS("VLC crashed previously")];
    [o_crashrep_desc_txt setStringValue: _NS("Do you want to send details on the crash to VLC's development team?\n\nIf you want, you can enter a few lines on what you did before VLC crashed along with other helpful information: a link to download a sample file, a URL of a network stream, ...")];
688
689
    [o_crashrep_includeEmail_ckb setTitle: _NS("I agree to be possibly contacted about this bugreport.")];
    [o_crashrep_includeEmail_txt setStringValue: _NS("Only your default E-Mail address will be submitted, including no further information.")];
690
691
}

692
693
694
695
#pragma mark -
#pragma mark Termination

- (void)applicationWillTerminate:(NSNotification *)notification
696
{
697
698
699
700
701
    playlist_t * p_playlist;
    vout_thread_t * p_vout;
    int returnedValue = 0;
 
    msg_Dbg( p_intf, "Terminating" );
702

703
704
    /* Make sure the manage_thread won't call -terminate: again */
    pthread_cancel( manage_thread );
705

706
707
    /* Make sure the intf object is getting killed */
    vlc_object_kill( p_intf );
Jérome Decoodt's avatar
Jérome Decoodt committed
708

709
710
    /* Make sure our manage_thread ends */
    pthread_join( manage_thread, NULL );
711

712
713
714
715
716
717
718
719
720
721
    /* Make sure the interfaceTimer is destroyed */
    [interfaceTimer invalidate];
    [interfaceTimer release];
    interfaceTimer = nil;

    /* make sure that the current volume is saved */
    config_PutInt( p_intf->p_libvlc, "volume", i_lastShownVolume );

    /* save the prefs if they were changed in the extended panel */
    if(o_extended && [o_extended getConfigChanged])
722
    {
723
        [o_extended savePrefs];
724
    }
725
 
726
    interaction_Unregister( p_intf );
727
    var_DelCallback( p_intf, "interaction", InteractCallback, self );
728

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

732
733
    [o_update end];

734
735
    /* release some other objects here, because it isn't sure whether dealloc
     * will be called later on */
hartman's avatar
-    
hartman committed
736

737
738
    if( nib_about_loaded )
        [o_about release];
hartman's avatar
hartman committed
739

740
    if( nib_prefs_loaded )
hartman's avatar
hartman committed
741
    {
742
743
744
        [o_sprefs release];
        [o_prefs release];
    }
745

746
747
748
749
750
751
    if( nib_open_loaded )
        [o_open release];

    if( nib_extended_loaded )
    {
        [o_extended release];
hartman's avatar
hartman committed
752
    }
753
754
755
756
757

    if( nib_bookmarks_loaded )
        [o_bookmarks release];

    if( o_info )
hartman's avatar
hartman committed
758
    {
759
760
        [o_info stopTimers];
        [o_info release];
hartman's avatar
hartman committed
761
762
    }

763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
    if( nib_wizard_loaded )
        [o_wizard release];

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

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

778
779
780
    /* unsubscribe from libvlc's debug messages */
    msg_Unsubscribe( p_intf->p_sys->p_sub );

781
782
783
784
785
786
787
788
789
790
    [o_msg_arr removeAllObjects];
    [o_msg_arr release];

    [o_msg_lock release];

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

    /* Kill the playlist, so that it doesn't accept new request
     * such as the play request from vlc.c (we are a blocking interface). */
dionoea's avatar
dionoea committed
791
    p_playlist = pl_Hold( p_intf );
792
793
794
    vlc_object_kill( p_playlist );
    pl_Release( p_intf );

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
795
    libvlc_Quit( p_intf->p_libvlc );
796

797
798
    [self setIntf:nil];

799
800
801
802
    /* Go back to Run() and make libvlc exit properly */
    if( jmpbuffer )
        longjmp( jmpbuffer, 1 );
    /* not reached */
hartman's avatar
hartman committed
803
804
}

805
806
#pragma mark -
#pragma mark Toolbar delegate
807

808
809
810
811
812
813
814
815
816
817
818
819
/* Our item identifiers */
static NSString * VLCToolbarMediaControl     = @"VLCToolbarMediaControl";

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

822
- (NSArray *) toolbarDefaultItemIdentifiers: (NSToolbar *) toolbar
823
{
824
825
826
827
    return [NSArray arrayWithObjects:
                        VLCToolbarMediaControl,
                        nil ];
}
828

829
830
831
- (NSToolbarItem *) toolbar:(NSToolbar *)toolbar itemForItemIdentifier:(NSString *)itemIdentifier willBeInsertedIntoToolbar:(BOOL)flag
{
    NSToolbarItem *toolbarItem = [[[NSToolbarItem alloc] initWithItemIdentifier: itemIdentifier] autorelease];
832

833
834
835
836
837
 
    if( [itemIdentifier isEqual: VLCToolbarMediaControl] )
    {
        [toolbarItem setLabel:@"Media Controls"];
        [toolbarItem setPaletteLabel:@"Media Controls"];
838

839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
        NSSize size = toolbarMediaControl.frame.size;
        [toolbarItem setView:toolbarMediaControl];
        [toolbarItem setMinSize:size];
        size.width += 1000.;
        [toolbarItem setMaxSize:size];

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

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

#pragma mark -
#pragma mark Other notification

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

911
912
913
914
915
916
917
918
919
920
921
/* 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];
}

922
923
924
925
/* Triggered when the computer goes to sleep */
- (void)computerWillSleep: (NSNotification *)notification
{
    /* Pause */
926
    if( p_intf->p_sys->i_play_status == PLAYING_S )
927
928
929
930
931
932
933
    {
        vlc_value_t val;
        val.i_int = config_GetInt( p_intf, "key-play-pause" );
        var_Set( p_intf->p_libvlc, "key-pressed", val );
    }
}

934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
#pragma mark -
#pragma mark File opening

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

    return( TRUE );
}

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

    return YES;
}

#pragma mark -
#pragma mark Apple Remote Control

961
962
/* 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 */
963
- (void) executeHoldActionForRemoteButton: (NSNumber*) buttonIdentifierNumber
964
{
965
    if(b_remote_button_hold)
966
    {
967
        switch([buttonIdentifierNumber intValue])
968
        {
969
            case kRemoteButtonRight_Hold:
970
                  [o_controls forward: self];
971
972
            break;
            case kRemoteButtonLeft_Hold:
973
974
975
976
977
978
979
                  [o_controls backward: self];
            break;
            case kRemoteButtonVolume_Plus_Hold:
                [o_controls volumeUp: self];
            break;
            case kRemoteButtonVolume_Minus_Hold:
                [o_controls volumeDown: self];
980
            break;
981
        }
982
        if(b_remote_button_hold)
983
        {
984
            /* trigger event */
985
            [self performSelector:@selector(executeHoldActionForRemoteButton:)
986
                         withObject:buttonIdentifierNumber
987
                         afterDelay:0.25];
988
989
990
991
        }
    }
}

992
/* Apple Remote callback */
993
994
995
- (void) appleRemoteButton: (AppleRemoteEventIdentifier)buttonIdentifier
               pressedDown: (BOOL) pressedDown
                clickCount: (unsigned int) count
996
997
998
999
{
    switch( buttonIdentifier )
    {
        case kRemoteButtonPlay:
1000
            if(count >= 2) {
1001
1002
1003
                [o_controls toogleFullscreen:self];
            } else {
                [o_controls play: self];
1004
            }
1005
            break;
Eric Petit's avatar
Eric Petit committed
1006
        case kRemoteButtonVolume_Plus:
1007
            [o_controls volumeUp: self];
Eric Petit's avatar
Eric Petit committed
1008
1009
            break;
        case kRemoteButtonVolume_Minus:
1010
            [o_controls volumeDown: self];
Eric Petit's avatar
Eric Petit committed
1011
            break;
1012
1013
1014
1015
1016
1017
1018
1019
        case kRemoteButtonRight:
            [o_controls next: self];
            break;
        case kRemoteButtonLeft:
            [o_controls prev: self];
            break;
        case kRemoteButtonRight_Hold:
        case kRemoteButtonLeft_Hold:
1020
1021