~ubuntu-branches/debian/wheezy/vlc/wheezy

« back to all changes in this revision

Viewing changes to modules/gui/macosx/intf.m

Tags: upstream-0.7.2.final
ImportĀ upstreamĀ versionĀ 0.7.2.final

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*****************************************************************************
 
2
 * intf.m: MacOS X interface module
 
3
 *****************************************************************************
 
4
 * Copyright (C) 2002-2004 VideoLAN
 
5
 * $Id: intf.m 7708 2004-05-17 22:14:25Z fkuehne $
 
6
 *
 
7
 * Authors: Jon Lech Johansen <jon-vl@nanocrew.net>
 
8
 *          Christophe Massiot <massiot@via.ecp.fr>
 
9
 *          Derk-Jan Hartman <hartman at videolan.org>
 
10
 *
 
11
 * This program is free software; you can redistribute it and/or modify
 
12
 * it under the terms of the GNU General Public License as published by
 
13
 * the Free Software Foundation; either version 2 of the License, or
 
14
 * (at your option) any later version.
 
15
 * 
 
16
 * This program is distributed in the hope that it will be useful,
 
17
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
18
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
19
 * GNU General Public License for more details.
 
20
 *
 
21
 * You should have received a copy of the GNU General Public License
 
22
 * along with this program; if not, write to the Free Software
 
23
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
 
24
 *****************************************************************************/
 
25
 
 
26
/*****************************************************************************
 
27
 * Preamble
 
28
 *****************************************************************************/
 
29
#include <stdlib.h>                                      /* malloc(), free() */
 
30
#include <sys/param.h>                                    /* for MAXPATHLEN */
 
31
#include <string.h>
 
32
#include <vlc_keys.h>
 
33
 
 
34
#include "intf.h"
 
35
#include "vout.h"
 
36
#include "prefs.h"
 
37
#include "playlist.h"
 
38
#include "info.h"
 
39
#include "controls.h"
 
40
 
 
41
/*****************************************************************************
 
42
 * Local prototypes.
 
43
 *****************************************************************************/
 
44
static void Run ( intf_thread_t *p_intf );
 
45
 
 
46
/*****************************************************************************
 
47
 * OpenIntf: initialize interface
 
48
 *****************************************************************************/
 
49
int E_(OpenIntf) ( vlc_object_t *p_this )
 
50
{   
 
51
    intf_thread_t *p_intf = (intf_thread_t*) p_this;
 
52
 
 
53
    p_intf->p_sys = malloc( sizeof( intf_sys_t ) );
 
54
    if( p_intf->p_sys == NULL )
 
55
    {
 
56
        return( 1 );
 
57
    }
 
58
 
 
59
    memset( p_intf->p_sys, 0, sizeof( *p_intf->p_sys ) );
 
60
    
 
61
    p_intf->p_sys->o_pool = [[NSAutoreleasePool alloc] init];
 
62
 
 
63
    /* Put Cocoa into multithread mode as soon as possible.
 
64
     * http://developer.apple.com/techpubs/macosx/Cocoa/
 
65
     * TasksAndConcepts/ProgrammingTopics/Multithreading/index.html
 
66
     * This thread does absolutely nothing at all. */
 
67
    [NSThread detachNewThreadSelector:@selector(self) toTarget:[NSString string] withObject:nil];
 
68
    
 
69
    p_intf->p_sys->o_sendport = [[NSPort port] retain];
 
70
    p_intf->p_sys->p_sub = msg_Subscribe( p_intf );
 
71
    p_intf->b_play = VLC_TRUE;
 
72
    p_intf->pf_run = Run;
 
73
    
 
74
    [VLCApplication sharedApplication];
 
75
    [NSApp setIntf: p_intf];
 
76
 
 
77
    [NSBundle loadNibNamed: @"MainMenu" owner: NSApp];
 
78
 
 
79
    return( 0 );
 
80
}
 
81
 
 
82
/*****************************************************************************
 
83
 * CloseIntf: destroy interface
 
84
 *****************************************************************************/
 
85
void E_(CloseIntf) ( vlc_object_t *p_this )
 
86
{
 
87
    intf_thread_t *p_intf = (intf_thread_t*) p_this;
 
88
 
 
89
    msg_Unsubscribe( p_intf, p_intf->p_sys->p_sub );
 
90
 
 
91
    [p_intf->p_sys->o_sendport release];
 
92
    [p_intf->p_sys->o_pool release];
 
93
 
 
94
    free( p_intf->p_sys );
 
95
}
 
96
 
 
97
/*****************************************************************************
 
98
 * Run: main loop
 
99
 *****************************************************************************/
 
100
static void Run( intf_thread_t *p_intf )
 
101
{
 
102
    /* Do it again - for some unknown reason, vlc_thread_create() often
 
103
     * fails to go to real-time priority with the first launched thread
 
104
     * (???) --Meuuh */
 
105
    vlc_thread_set_priority( p_intf, VLC_THREAD_PRIORITY_LOW );
 
106
 
 
107
    [NSApp run];
 
108
}
 
109
 
 
110
/*****************************************************************************
 
111
 * VLCApplication implementation 
 
112
 *****************************************************************************/
 
113
@implementation VLCApplication
 
114
 
 
115
- (NSString *)localizedString:(char *)psz
 
116
{
 
117
    NSString * o_str = nil;
 
118
 
 
119
    if( psz != NULL )
 
120
    {
 
121
        o_str = [[[NSString alloc] initWithUTF8String: psz] autorelease];
 
122
    }
 
123
    if ( o_str == NULL )
 
124
    {
 
125
        msg_Err( p_intf, "could not translate: %s", psz );
 
126
    }
 
127
 
 
128
    return( o_str );
 
129
}
 
130
 
 
131
- (char *)delocalizeString:(NSString *)id
 
132
{
 
133
    NSData * o_data = [id dataUsingEncoding: NSUTF8StringEncoding
 
134
                          allowLossyConversion: NO];
 
135
    char * psz_string;
 
136
 
 
137
    if ( o_data == nil )
 
138
    {
 
139
        o_data = [id dataUsingEncoding: NSUTF8StringEncoding
 
140
                     allowLossyConversion: YES];
 
141
        psz_string = malloc( [o_data length] + 1 ); 
 
142
        [o_data getBytes: psz_string];
 
143
        psz_string[ [o_data length] ] = '\0';
 
144
        msg_Err( p_intf, "cannot convert to wanted encoding: %s",
 
145
                 psz_string );
 
146
    }
 
147
    else
 
148
    {
 
149
        psz_string = malloc( [o_data length] + 1 ); 
 
150
        [o_data getBytes: psz_string];
 
151
        psz_string[ [o_data length] ] = '\0';
 
152
    }
 
153
 
 
154
    return psz_string;
 
155
}
 
156
 
 
157
/* i_width is in pixels */
 
158
- (NSString *)wrapString: (NSString *)o_in_string toWidth: (int) i_width
 
159
{
 
160
    NSMutableString *o_wrapped;
 
161
    NSString *o_out_string;
 
162
    NSRange glyphRange, effectiveRange, charRange;
 
163
    NSRect lineFragmentRect;
 
164
    unsigned glyphIndex, breaksInserted = 0;
 
165
 
 
166
    NSTextStorage *o_storage = [[NSTextStorage alloc] initWithString: o_in_string
 
167
        attributes: [NSDictionary dictionaryWithObjectsAndKeys:
 
168
        [NSFont labelFontOfSize: 0.0], NSFontAttributeName, nil]];
 
169
    NSLayoutManager *o_layout_manager = [[NSLayoutManager alloc] init];
 
170
    NSTextContainer *o_container = [[NSTextContainer alloc]
 
171
        initWithContainerSize: NSMakeSize(i_width, 2000)];
 
172
    
 
173
    [o_layout_manager addTextContainer: o_container];
 
174
    [o_container release];
 
175
    [o_storage addLayoutManager: o_layout_manager];
 
176
    [o_layout_manager release];
 
177
        
 
178
    o_wrapped = [o_in_string mutableCopy];
 
179
    glyphRange = [o_layout_manager glyphRangeForTextContainer: o_container];
 
180
    
 
181
    for( glyphIndex = glyphRange.location ; glyphIndex < NSMaxRange(glyphRange) ;
 
182
            glyphIndex += effectiveRange.length) {
 
183
        lineFragmentRect = [o_layout_manager lineFragmentRectForGlyphAtIndex: glyphIndex
 
184
                                            effectiveRange: &effectiveRange];
 
185
        charRange = [o_layout_manager characterRangeForGlyphRange: effectiveRange
 
186
                                    actualGlyphRange: &effectiveRange];
 
187
        if ([o_wrapped lineRangeForRange:
 
188
                NSMakeRange(charRange.location + breaksInserted, charRange.length)].length > charRange.length) {
 
189
            [o_wrapped insertString: @"\n" atIndex: NSMaxRange(charRange) + breaksInserted];
 
190
            breaksInserted++;
 
191
        }
 
192
    }
 
193
    o_out_string = [NSString stringWithString: o_wrapped];
 
194
    [o_wrapped release];
 
195
    [o_storage release];
 
196
    
 
197
    return o_out_string;
 
198
}
 
199
 
 
200
- (void)setIntf:(intf_thread_t *)_p_intf
 
201
{
 
202
    p_intf = _p_intf;
 
203
}
 
204
 
 
205
- (intf_thread_t *)getIntf
 
206
{
 
207
    return( p_intf );
 
208
}
 
209
 
 
210
- (void)terminate:(id)sender
 
211
{
 
212
    p_intf->p_vlc->b_die = VLC_TRUE;
 
213
    [super terminate:sender];
 
214
}
 
215
 
 
216
 
 
217
/*****************************************************************************
 
218
 * hasDefinedShortcutKey: Check to see if the key press is a defined VLC
 
219
 * shortcut key.  If it is, pass it off to VLC for handling and return YES,
 
220
 * otherwise ignore it and return NO (where it will get handled by Cocoa).
 
221
 *****************************************************************************/
 
222
- (BOOL)hasDefinedShortcutKey:(NSEvent *)o_event
 
223
{
 
224
    unichar key = 0;
 
225
    vlc_value_t val;
 
226
    unsigned int i_pressed_modifiers = 0;
 
227
    struct hotkey *p_hotkeys;
 
228
    int i;
 
229
 
 
230
    val.i_int = 0;
 
231
    p_hotkeys = p_intf->p_vlc->p_hotkeys;
 
232
 
 
233
    i_pressed_modifiers = [o_event modifierFlags];
 
234
 
 
235
    if( i_pressed_modifiers & NSShiftKeyMask )
 
236
        val.i_int |= KEY_MODIFIER_SHIFT;
 
237
    if( i_pressed_modifiers & NSControlKeyMask )
 
238
        val.i_int |= KEY_MODIFIER_CTRL;
 
239
    if( i_pressed_modifiers & NSAlternateKeyMask )
 
240
        val.i_int |= KEY_MODIFIER_ALT;
 
241
    if( i_pressed_modifiers & NSCommandKeyMask )
 
242
        val.i_int |= KEY_MODIFIER_COMMAND;
 
243
 
 
244
    key = [[o_event charactersIgnoringModifiers] characterAtIndex: 0];
 
245
 
 
246
    val.i_int |= CocoaKeyToVLC( key );
 
247
 
 
248
    for( i = 0; p_hotkeys[i].psz_action != NULL; i++ )
 
249
    {
 
250
        if( p_hotkeys[i].i_key == val.i_int )
 
251
        {
 
252
            var_Set( p_intf->p_vlc, "key-pressed", val );
 
253
            return YES;
 
254
        }
 
255
    }
 
256
 
 
257
    return NO;
 
258
}
 
259
 
 
260
@end
 
261
 
 
262
int ExecuteOnMainThread( id target, SEL sel, void * p_arg )
 
263
{
 
264
    int i_ret = 0;
 
265
 
 
266
    NSAutoreleasePool * o_pool = [[NSAutoreleasePool alloc] init];
 
267
 
 
268
    if( [target respondsToSelector: @selector(performSelectorOnMainThread:
 
269
                                             withObject:waitUntilDone:)] )
 
270
    {
 
271
        [target performSelectorOnMainThread: sel
 
272
                withObject: [NSValue valueWithPointer: p_arg]
 
273
                waitUntilDone: YES];
 
274
    }
 
275
    else if( NSApp != nil && [NSApp respondsToSelector: @selector(getIntf)] ) 
 
276
    {
 
277
        NSValue * o_v1;
 
278
        NSValue * o_v2;
 
279
        NSArray * o_array;
 
280
        NSPort * o_recv_port;
 
281
        NSInvocation * o_inv;
 
282
        NSPortMessage * o_msg;
 
283
        intf_thread_t * p_intf;
 
284
        NSConditionLock * o_lock;
 
285
        NSMethodSignature * o_sig;
 
286
 
 
287
        id * val[] = { &o_lock, &o_v2 };
 
288
 
 
289
        p_intf = (intf_thread_t *)[NSApp getIntf];
 
290
 
 
291
        o_recv_port = [[NSPort port] retain];
 
292
        o_v1 = [NSValue valueWithPointer: val]; 
 
293
        o_v2 = [NSValue valueWithPointer: p_arg];
 
294
 
 
295
        o_sig = [target methodSignatureForSelector: sel];
 
296
        o_inv = [NSInvocation invocationWithMethodSignature: o_sig];
 
297
        [o_inv setArgument: &o_v1 atIndex: 2];
 
298
        [o_inv setTarget: target];
 
299
        [o_inv setSelector: sel];
 
300
 
 
301
        o_array = [NSArray arrayWithObject:
 
302
            [NSData dataWithBytes: &o_inv length: sizeof(o_inv)]];
 
303
        o_msg = [[NSPortMessage alloc]
 
304
            initWithSendPort: p_intf->p_sys->o_sendport
 
305
            receivePort: o_recv_port components: o_array];
 
306
 
 
307
        o_lock = [[NSConditionLock alloc] initWithCondition: 0];
 
308
        [o_msg sendBeforeDate: [NSDate distantPast]];
 
309
        [o_lock lockWhenCondition: 1];
 
310
        [o_lock unlock];
 
311
        [o_lock release];
 
312
 
 
313
        [o_msg release];
 
314
        [o_recv_port release];
 
315
    } 
 
316
    else
 
317
    {
 
318
        i_ret = 1;
 
319
    }
 
320
 
 
321
    [o_pool release];
 
322
 
 
323
    return( i_ret );
 
324
}
 
325
 
 
326
/*****************************************************************************
 
327
 * playlistChanged: Callback triggered by the intf-change playlist
 
328
 * variable, to let the intf update the playlist.
 
329
 *****************************************************************************/
 
330
int PlaylistChanged( vlc_object_t *p_this, const char *psz_variable,
 
331
                     vlc_value_t old_val, vlc_value_t new_val, void *param )
 
332
{
 
333
    intf_thread_t * p_intf = [NSApp getIntf];
 
334
    p_intf->p_sys->b_playlist_update = TRUE;
 
335
    p_intf->p_sys->b_intf_update = TRUE;
 
336
    return VLC_SUCCESS;
 
337
}
 
338
 
 
339
static struct
 
340
{
 
341
    unichar i_nskey;
 
342
    unsigned int i_vlckey;
 
343
} nskeys_to_vlckeys[] = 
 
344
{
 
345
    { NSUpArrowFunctionKey, KEY_UP },
 
346
    { NSDownArrowFunctionKey, KEY_DOWN },
 
347
    { NSLeftArrowFunctionKey, KEY_LEFT },
 
348
    { NSRightArrowFunctionKey, KEY_RIGHT },
 
349
    { NSF1FunctionKey, KEY_F1 },
 
350
    { NSF2FunctionKey, KEY_F2 },
 
351
    { NSF3FunctionKey, KEY_F3 },
 
352
    { NSF4FunctionKey, KEY_F4 },
 
353
    { NSF5FunctionKey, KEY_F5 },
 
354
    { NSF6FunctionKey, KEY_F6 },
 
355
    { NSF7FunctionKey, KEY_F7 },
 
356
    { NSF8FunctionKey, KEY_F8 },
 
357
    { NSF9FunctionKey, KEY_F9 },
 
358
    { NSF10FunctionKey, KEY_F10 },
 
359
    { NSF11FunctionKey, KEY_F11 },
 
360
    { NSF12FunctionKey, KEY_F12 },
 
361
    { NSHomeFunctionKey, KEY_HOME },
 
362
    { NSEndFunctionKey, KEY_END },
 
363
    { NSPageUpFunctionKey, KEY_PAGEUP },
 
364
    { NSPageDownFunctionKey, KEY_PAGEDOWN },
 
365
    { NSTabCharacter, KEY_TAB },
 
366
    { NSCarriageReturnCharacter, KEY_ENTER },
 
367
    { NSEnterCharacter, KEY_ENTER },
 
368
    { NSBackspaceCharacter, KEY_BACKSPACE },
 
369
    { (unichar) ' ', KEY_SPACE },
 
370
    { (unichar) 0x1b, KEY_ESC },
 
371
    {0,0}
 
372
};
 
373
 
 
374
unichar VLCKeyToCocoa( unsigned int i_key )
 
375
{
 
376
    unsigned int i;
 
377
    
 
378
    for( i = 0; nskeys_to_vlckeys[i].i_vlckey != 0; i++ )
 
379
    {
 
380
        if( nskeys_to_vlckeys[i].i_vlckey == (i_key & ~KEY_MODIFIER) )
 
381
        {
 
382
            return nskeys_to_vlckeys[i].i_nskey;
 
383
        }
 
384
    }
 
385
    return (unichar)(i_key & ~KEY_MODIFIER);
 
386
}
 
387
 
 
388
unsigned int CocoaKeyToVLC( unichar i_key )
 
389
{
 
390
    unsigned int i;
 
391
    
 
392
    for( i = 0; nskeys_to_vlckeys[i].i_nskey != 0; i++ )
 
393
    {
 
394
        if( nskeys_to_vlckeys[i].i_nskey == i_key )
 
395
        {
 
396
            return nskeys_to_vlckeys[i].i_vlckey;
 
397
        }
 
398
    }
 
399
    return (unsigned int)i_key;
 
400
}
 
401
 
 
402
unsigned int VLCModifiersToCocoa( unsigned int i_key )
 
403
{
 
404
    unsigned int new = 0;
 
405
    if( i_key & KEY_MODIFIER_COMMAND )
 
406
        new |= NSCommandKeyMask;
 
407
    if( i_key & KEY_MODIFIER_ALT )
 
408
        new |= NSAlternateKeyMask;
 
409
    if( i_key & KEY_MODIFIER_SHIFT )
 
410
        new |= NSShiftKeyMask;
 
411
    if( i_key & KEY_MODIFIER_CTRL )
 
412
        new |= NSControlKeyMask;
 
413
    return new;
 
414
}
 
415
 
 
416
/*****************************************************************************
 
417
 * VLCMain implementation 
 
418
 *****************************************************************************/
 
419
@implementation VLCMain
 
420
 
 
421
- (void)awakeFromNib
 
422
{
 
423
    unsigned int i_key = 0;
 
424
    intf_thread_t * p_intf = [NSApp getIntf];
 
425
    playlist_t *p_playlist;
 
426
    vlc_value_t val;
 
427
 
 
428
    [self initStrings];
 
429
    [o_window setExcludedFromWindowsMenu: TRUE];
 
430
    [o_msgs_panel setExcludedFromWindowsMenu: TRUE];
 
431
    [o_msgs_panel setDelegate: self];
 
432
    
 
433
    i_key = config_GetInt( p_intf, "key-quit" );
 
434
    [o_mi_quit setKeyEquivalent: [NSString stringWithFormat:@"%C", VLCKeyToCocoa( i_key )]];
 
435
    [o_mi_quit setKeyEquivalentModifierMask: VLCModifiersToCocoa(i_key)];
 
436
    i_key = config_GetInt( p_intf, "key-play-pause" );
 
437
    [o_mi_play setKeyEquivalent: [NSString stringWithFormat:@"%C", VLCKeyToCocoa( i_key )]];
 
438
    [o_mi_play setKeyEquivalentModifierMask: VLCModifiersToCocoa(i_key)];
 
439
    i_key = config_GetInt( p_intf, "key-stop" );
 
440
    [o_mi_stop setKeyEquivalent: [NSString stringWithFormat:@"%C", VLCKeyToCocoa( i_key )]];
 
441
    [o_mi_stop setKeyEquivalentModifierMask: VLCModifiersToCocoa(i_key)];
 
442
    i_key = config_GetInt( p_intf, "key-faster" );
 
443
    [o_mi_faster setKeyEquivalent: [NSString stringWithFormat:@"%C", VLCKeyToCocoa( i_key )]];
 
444
    [o_mi_faster setKeyEquivalentModifierMask: VLCModifiersToCocoa(i_key)];
 
445
    i_key = config_GetInt( p_intf, "key-slower" );
 
446
    [o_mi_slower setKeyEquivalent: [NSString stringWithFormat:@"%C", VLCKeyToCocoa( i_key )]];
 
447
    [o_mi_slower setKeyEquivalentModifierMask: VLCModifiersToCocoa(i_key)];
 
448
    i_key = config_GetInt( p_intf, "key-prev" );
 
449
    [o_mi_previous setKeyEquivalent: [NSString stringWithFormat:@"%C", VLCKeyToCocoa( i_key )]];
 
450
    [o_mi_previous setKeyEquivalentModifierMask: VLCModifiersToCocoa(i_key)];
 
451
    i_key = config_GetInt( p_intf, "key-next" );
 
452
    [o_mi_next setKeyEquivalent: [NSString stringWithFormat:@"%C", VLCKeyToCocoa( i_key )]];
 
453
    [o_mi_next setKeyEquivalentModifierMask: VLCModifiersToCocoa(i_key)];
 
454
    i_key = config_GetInt( p_intf, "key-jump+10sec" );
 
455
    [o_mi_fwd setKeyEquivalent: [NSString stringWithFormat:@"%C", VLCKeyToCocoa( i_key )]];
 
456
    [o_mi_fwd setKeyEquivalentModifierMask: VLCModifiersToCocoa(i_key)];
 
457
    i_key = config_GetInt( p_intf, "key-jump-10sec" );
 
458
    [o_mi_bwd setKeyEquivalent: [NSString stringWithFormat:@"%C", VLCKeyToCocoa( i_key )]];
 
459
    [o_mi_bwd setKeyEquivalentModifierMask: VLCModifiersToCocoa(i_key)];
 
460
    i_key = config_GetInt( p_intf, "key-jump+1min" );
 
461
    [o_mi_fwd1m setKeyEquivalent: [NSString stringWithFormat:@"%C", VLCKeyToCocoa( i_key )]];
 
462
    [o_mi_fwd1m setKeyEquivalentModifierMask: VLCModifiersToCocoa(i_key)];
 
463
    i_key = config_GetInt( p_intf, "key-jump-1min" );
 
464
    [o_mi_bwd1m setKeyEquivalent: [NSString stringWithFormat:@"%C", VLCKeyToCocoa( i_key )]];
 
465
    [o_mi_bwd1m setKeyEquivalentModifierMask: VLCModifiersToCocoa(i_key)];
 
466
    i_key = config_GetInt( p_intf, "key-jump+5min" );
 
467
    [o_mi_fwd5m setKeyEquivalent: [NSString stringWithFormat:@"%C", VLCKeyToCocoa( i_key )]];
 
468
    [o_mi_fwd5m setKeyEquivalentModifierMask: VLCModifiersToCocoa(i_key)];
 
469
    i_key = config_GetInt( p_intf, "key-jump-5min" );
 
470
    [o_mi_bwd5m setKeyEquivalent: [NSString stringWithFormat:@"%C", VLCKeyToCocoa( i_key )]];
 
471
    [o_mi_bwd5m setKeyEquivalentModifierMask: VLCModifiersToCocoa(i_key)];
 
472
    i_key = config_GetInt( p_intf, "key-vol-up" );
 
473
    [o_mi_vol_up setKeyEquivalent: [NSString stringWithFormat:@"%C", VLCKeyToCocoa( i_key )]];
 
474
    [o_mi_vol_up setKeyEquivalentModifierMask: VLCModifiersToCocoa(i_key)];
 
475
    i_key = config_GetInt( p_intf, "key-vol-down" );
 
476
    [o_mi_vol_down setKeyEquivalent: [NSString stringWithFormat:@"%C", VLCKeyToCocoa( i_key )]];
 
477
    [o_mi_vol_down setKeyEquivalentModifierMask: VLCModifiersToCocoa(i_key)];
 
478
    i_key = config_GetInt( p_intf, "key-vol-mute" );
 
479
    [o_mi_mute setKeyEquivalent: [NSString stringWithFormat:@"%C", VLCKeyToCocoa( i_key )]];
 
480
    [o_mi_mute setKeyEquivalentModifierMask: VLCModifiersToCocoa(i_key)];
 
481
    i_key = config_GetInt( p_intf, "key-fullscreen" );
 
482
    [o_mi_fullscreen setKeyEquivalent: [NSString stringWithFormat:@"%C", VLCKeyToCocoa( i_key )]];
 
483
    [o_mi_fullscreen setKeyEquivalentModifierMask: VLCModifiersToCocoa(i_key)];
 
484
 
 
485
    var_Create( p_intf, "intf-change", VLC_VAR_BOOL );
 
486
 
 
487
    [self setSubmenusEnabled: FALSE];
 
488
    [self manageVolumeSlider];
 
489
    
 
490
    p_playlist = (playlist_t *) vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
 
491
 
 
492
    if( p_playlist )
 
493
    {
 
494
        /* Check if we need to start playing */
 
495
        if( p_intf->b_play )
 
496
        {
 
497
            playlist_Play( p_playlist );
 
498
        }
 
499
        [o_btn_fullscreen setState: ( var_Get( p_playlist, "fullscreen", &val )>=0 && val.b_bool )];
 
500
        vlc_object_release( p_playlist );
 
501
    }
 
502
}
 
503
 
 
504
- (void)initStrings
 
505
{
 
506
    [o_window setTitle: _NS("VLC - Controller")];
 
507
    [o_scrollfield setStringValue: _NS("VLC media player")];
 
508
 
 
509
    /* button controls */
 
510
    [o_btn_prev setToolTip: _NS("Previous")];
 
511
    [o_btn_rewind setToolTip: _NS("Rewind")];
 
512
    [o_btn_play setToolTip: _NS("Play")];
 
513
    [o_btn_stop setToolTip: _NS("Stop")];
 
514
    [o_btn_ff setToolTip: _NS("Fast Forward")];
 
515
    [o_btn_next setToolTip: _NS("Next")];
 
516
    [o_btn_fullscreen setToolTip: _NS("Fullscreen")];
 
517
    [o_volumeslider setToolTip: _NS("Volume")];
 
518
    [o_timeslider setToolTip: _NS("Position")];
 
519
 
 
520
    /* messages panel */ 
 
521
    [o_msgs_panel setTitle: _NS("Messages")];
 
522
    [o_msgs_btn_crashlog setTitle: _NS("Open CrashLog")];
 
523
 
 
524
    /* main menu */
 
525
    [o_mi_about setTitle: _NS("About VLC media player")];
 
526
    [o_mi_prefs setTitle: _NS("Preferences...")];
 
527
    [o_mi_add_intf setTitle: _NS("Add Interface")];
 
528
    [o_mu_add_intf setTitle: _NS("Add Interface")];
 
529
    [o_mi_services setTitle: _NS("Services")];
 
530
    [o_mi_hide setTitle: _NS("Hide VLC")];
 
531
    [o_mi_hide_others setTitle: _NS("Hide Others")];
 
532
    [o_mi_show_all setTitle: _NS("Show All")];
 
533
    [o_mi_quit setTitle: _NS("Quit VLC")];
 
534
 
 
535
    [o_mu_file setTitle: _ANS("1:File")];
 
536
    [o_mi_open_generic setTitle: _NS("Open File...")];
 
537
    [o_mi_open_file setTitle: _NS("Quick Open File...")];
 
538
    [o_mi_open_disc setTitle: _NS("Open Disc...")];
 
539
    [o_mi_open_net setTitle: _NS("Open Network...")];
 
540
    [o_mi_open_recent setTitle: _NS("Open Recent")];
 
541
    [o_mi_open_recent_cm setTitle: _NS("Clear Menu")];
 
542
 
 
543
    [o_mu_edit setTitle: _NS("Edit")];
 
544
    [o_mi_cut setTitle: _NS("Cut")];
 
545
    [o_mi_copy setTitle: _NS("Copy")];
 
546
    [o_mi_paste setTitle: _NS("Paste")];
 
547
    [o_mi_clear setTitle: _NS("Clear")];
 
548
    [o_mi_select_all setTitle: _NS("Select All")];
 
549
 
 
550
    [o_mu_controls setTitle: _NS("Controls")];
 
551
    [o_mi_play setTitle: _NS("Play")];
 
552
    [o_mi_stop setTitle: _NS("Stop")];
 
553
    [o_mi_faster setTitle: _NS("Faster")];
 
554
    [o_mi_slower setTitle: _NS("Slower")];
 
555
    [o_mi_previous setTitle: _NS("Previous")];
 
556
    [o_mi_next setTitle: _NS("Next")];
 
557
    [o_mi_random setTitle: _NS("Random")];
 
558
    [o_mi_repeat setTitle: _NS("Repeat One")];
 
559
    [o_mi_loop setTitle: _NS("Repeat All")];
 
560
    [o_mi_fwd setTitle: _NS("Step Forward")];
 
561
    [o_mi_bwd setTitle: _NS("Step Backward")];
 
562
 
 
563
    [o_mi_program setTitle: _NS("Program")];
 
564
    [o_mu_program setTitle: _NS("Program")];
 
565
    [o_mi_title setTitle: _NS("Title")];
 
566
    [o_mu_title setTitle: _NS("Title")];
 
567
    [o_mi_chapter setTitle: _NS("Chapter")];
 
568
    [o_mu_chapter setTitle: _NS("Chapter")];
 
569
    
 
570
    [o_mu_audio setTitle: _NS("Audio")];
 
571
    [o_mi_vol_up setTitle: _NS("Volume Up")];
 
572
    [o_mi_vol_down setTitle: _NS("Volume Down")];
 
573
    [o_mi_mute setTitle: _NS("Mute")];
 
574
    [o_mi_audiotrack setTitle: _NS("Audio Track")];
 
575
    [o_mu_audiotrack setTitle: _NS("Audio Track")];
 
576
    [o_mi_channels setTitle: _NS("Audio Channels")];
 
577
    [o_mu_channels setTitle: _NS("Audio Channels")];
 
578
    [o_mi_device setTitle: _NS("Audio Device")];
 
579
    [o_mu_device setTitle: _NS("Audio Device")];
 
580
    [o_mi_visual setTitle: _NS("Visualizations")];
 
581
    [o_mu_visual setTitle: _NS("Visualizations")];
 
582
    
 
583
    [o_mu_video setTitle: _NS("Video")];
 
584
    [o_mi_half_window setTitle: _NS("Half Size")];
 
585
    [o_mi_normal_window setTitle: _NS("Normal Size")];
 
586
    [o_mi_double_window setTitle: _NS("Double Size")];
 
587
    [o_mi_fittoscreen setTitle: _NS("Fit to Screen")];
 
588
    [o_mi_fullscreen setTitle: _NS("Fullscreen")];
 
589
    [o_mi_floatontop setTitle: _NS("Float on Top")];
 
590
    [o_mi_videotrack setTitle: _NS("Video Track")];
 
591
    [o_mu_videotrack setTitle: _NS("Video Track")];
 
592
    [o_mi_screen setTitle: _NS("Video Device")];
 
593
    [o_mu_screen setTitle: _NS("Video Device")];
 
594
    [o_mi_subtitle setTitle: _NS("Subtitles Track")];
 
595
    [o_mu_subtitle setTitle: _NS("Subtitles Track")];
 
596
    [o_mi_deinterlace setTitle: _NS("Deinterlace")];
 
597
    [o_mu_deinterlace setTitle: _NS("Deinterlace")];
 
598
 
 
599
    [o_mu_window setTitle: _NS("Window")];
 
600
    [o_mi_minimize setTitle: _NS("Minimize Window")];
 
601
    [o_mi_close_window setTitle: _NS("Close Window")];
 
602
    [o_mi_controller setTitle: _NS("Controller")];
 
603
    [o_mi_playlist setTitle: _NS("Playlist")];
 
604
    [o_mi_info setTitle: _NS("Info")];
 
605
    [o_mi_messages setTitle: _NS("Messages")];
 
606
 
 
607
    [o_mi_bring_atf setTitle: _NS("Bring All to Front")];
 
608
 
 
609
    [o_mu_help setTitle: _NS("Help")];
 
610
    [o_mi_readme setTitle: _NS("ReadMe...")];
 
611
    [o_mi_documentation setTitle: _NS("Online Documentation")];
 
612
    [o_mi_reportabug setTitle: _NS("Report a Bug")];
 
613
    [o_mi_website setTitle: _NS("VideoLAN Website")];
 
614
    [o_mi_license setTitle: _NS("License")];
 
615
 
 
616
    /* dock menu */
 
617
    [o_dmi_play setTitle: _NS("Play")];
 
618
    [o_dmi_stop setTitle: _NS("Stop")];
 
619
    [o_dmi_next setTitle: _NS("Next")];
 
620
    [o_dmi_previous setTitle: _NS("Previous")];
 
621
    [o_dmi_mute setTitle: _NS("Mute")];
 
622
 
 
623
    /* error panel */
 
624
    [o_error setTitle: _NS("Error")];
 
625
    [o_err_lbl setStringValue: _NS("An error has occurred which probably prevented the execution of your request:")];
 
626
    [o_err_bug_lbl setStringValue: _NS("If you believe that it is a bug, please follow the instructions at:")]; 
 
627
    [o_err_btn_msgs setTitle: _NS("Open Messages Window")];
 
628
    [o_err_btn_dismiss setTitle: _NS("Dismiss")];
 
629
    [o_err_ckbk_surpress setTitle: _NS("Suppress further errors")];
 
630
 
 
631
    [o_info_window setTitle: _NS("Info")];
 
632
}
 
633
 
 
634
- (void)applicationWillFinishLaunching:(NSNotification *)o_notification
 
635
{
 
636
    intf_thread_t * p_intf = [NSApp getIntf];
 
637
 
 
638
    o_msg_lock = [[NSLock alloc] init];
 
639
    o_msg_arr = [[NSMutableArray arrayWithCapacity: 200] retain];
 
640
 
 
641
    o_img_play = [[NSImage imageNamed: @"play"] retain];
 
642
    o_img_play_pressed = [[NSImage imageNamed: @"play_blue"] retain];
 
643
    o_img_pause = [[NSImage imageNamed: @"pause"] retain];
 
644
    o_img_pause_pressed = [[NSImage imageNamed: @"pause_blue"] retain];
 
645
 
 
646
    [p_intf->p_sys->o_sendport setDelegate: self];
 
647
    [[NSRunLoop currentRunLoop] 
 
648
        addPort: p_intf->p_sys->o_sendport
 
649
        forMode: NSDefaultRunLoopMode];
 
650
 
 
651
    [NSTimer scheduledTimerWithTimeInterval: 0.5
 
652
        target: self selector: @selector(manageIntf:)
 
653
        userInfo: nil repeats: FALSE];
 
654
 
 
655
    [NSThread detachNewThreadSelector: @selector(manage)
 
656
        toTarget: self withObject: nil];
 
657
        
 
658
    [o_controls setupVarMenuItem: o_mi_add_intf target: (vlc_object_t *)p_intf
 
659
        var: "intf-add" selector: @selector(toggleVar:)];
 
660
 
 
661
    vlc_thread_set_priority( p_intf, VLC_THREAD_PRIORITY_LOW );
 
662
}
 
663
 
 
664
- (BOOL)application:(NSApplication *)o_app openFile:(NSString *)o_filename
 
665
{
 
666
    NSDictionary *o_dic = [NSDictionary dictionaryWithObjectsAndKeys: o_filename, @"ITEM_URL", nil];
 
667
    [o_playlist appendArray:
 
668
        [NSArray arrayWithObject: o_dic] atPos: -1 enqueue: NO];
 
669
            
 
670
    return( TRUE );
 
671
}
 
672
 
 
673
- (id)getControls
 
674
{
 
675
    if ( o_controls )
 
676
    {
 
677
        return o_controls;
 
678
    }
 
679
    return nil;
 
680
}
 
681
 
 
682
- (id)getPlaylist
 
683
{
 
684
    if ( o_playlist )
 
685
    {
 
686
        return o_playlist;
 
687
    }
 
688
    return nil;
 
689
}
 
690
 
 
691
- (id)getInfo
 
692
{
 
693
    if ( o_info )
 
694
    {
 
695
        return o_info;
 
696
    }
 
697
    return  nil;
 
698
}
 
699
 
 
700
- (void)manage
 
701
{
 
702
    NSDate * o_sleep_date;
 
703
    intf_thread_t * p_intf = [NSApp getIntf];
 
704
    NSAutoreleasePool * o_pool = [[NSAutoreleasePool alloc] init];
 
705
 
 
706
    vlc_thread_set_priority( p_intf, VLC_THREAD_PRIORITY_LOW );
 
707
 
 
708
    while( !p_intf->b_die )
 
709
    {
 
710
        playlist_t * p_playlist;
 
711
        vlc_value_t val;
 
712
        vlc_mutex_lock( &p_intf->change_lock );
 
713
 
 
714
        p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, 
 
715
                                              FIND_ANYWHERE );
 
716
 
 
717
        if( p_playlist != NULL )
 
718
        {
 
719
            var_AddCallback( p_playlist, "intf-change", PlaylistChanged, self );
 
720
            var_AddCallback( p_playlist, "item-change", PlaylistChanged, self );
 
721
            var_AddCallback( p_playlist, "playlist-current", PlaylistChanged, self );
 
722
 
 
723
#define p_input p_playlist->p_input
 
724
        
 
725
            if( p_input )
 
726
            {
 
727
                if( !p_input->b_die )
 
728
                {
 
729
                    vlc_value_t val;
 
730
 
 
731
                    /* New input or stream map change */
 
732
                    if( p_input->stream.b_changed )
 
733
                    {
 
734
                        msg_Dbg( p_intf, "stream has changed, refreshing interface" );
 
735
                        p_intf->p_sys->b_playing = TRUE;
 
736
                        p_intf->p_sys->b_current_title_update = 1;
 
737
                        p_input->stream.b_changed = 0;
 
738
                        p_intf->p_sys->b_intf_update = TRUE;
 
739
                    }
 
740
 
 
741
                    if( var_Get( (vlc_object_t *)p_input, "intf-change", &val )
 
742
                        >= 0 && val.b_bool )
 
743
                    {
 
744
                        p_intf->p_sys->b_input_update = TRUE;
 
745
                    }
 
746
                }
 
747
            }
 
748
            else if( p_intf->p_sys->b_playing && !p_intf->b_die )
 
749
            {
 
750
                p_intf->p_sys->b_playing = FALSE;
 
751
            }
 
752
            
 
753
#undef p_input
 
754
            vlc_object_release( p_playlist );
 
755
 
 
756
            if( var_Get( p_intf, "intf-change", &val )
 
757
                        >= 0 && val.b_bool )
 
758
            {
 
759
                p_intf->p_sys->b_fullscreen_update = TRUE;
 
760
            }
 
761
            val.b_bool = VLC_FALSE;
 
762
            var_Set( p_intf,"intf-change",val);
 
763
        }
 
764
 
 
765
        vlc_mutex_unlock( &p_intf->change_lock );
 
766
 
 
767
        o_sleep_date = [NSDate dateWithTimeIntervalSinceNow: .5];
 
768
        [NSThread sleepUntilDate: o_sleep_date];
 
769
    }
 
770
 
 
771
    [self terminate];
 
772
    [o_pool release];
 
773
}
 
774
 
 
775
- (void)manageIntf:(NSTimer *)o_timer
 
776
{
 
777
    intf_thread_t * p_intf = [NSApp getIntf];
 
778
 
 
779
    if( p_intf->p_vlc->b_die == VLC_TRUE )
 
780
    {
 
781
        [o_timer invalidate];
 
782
        return;
 
783
    }
 
784
 
 
785
    playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
 
786
                                                       FIND_ANYWHERE );
 
787
 
 
788
    if( p_playlist == NULL )
 
789
    {
 
790
        return;
 
791
    }
 
792
 
 
793
    if ( p_intf->p_sys->b_playlist_update )
 
794
    {
 
795
        [o_playlist playlistUpdated];
 
796
        p_intf->p_sys->b_playlist_update = VLC_FALSE;
 
797
    }
 
798
 
 
799
    if( p_intf->p_sys->b_current_title_update )
 
800
    {
 
801
        vout_thread_t *p_vout = vlc_object_find( p_intf, VLC_OBJECT_VOUT,
 
802
                                                FIND_ANYWHERE );
 
803
 
 
804
        vlc_mutex_lock( &p_playlist->object_lock );
 
805
        [o_scrollfield setStringValue: [NSString stringWithUTF8String: 
 
806
            p_playlist->pp_items[p_playlist->i_index]->input.psz_name]]; 
 
807
        vlc_mutex_unlock( &p_playlist->object_lock );
 
808
 
 
809
        if( p_vout != NULL )
 
810
        {
 
811
            id o_vout_wnd;
 
812
            NSEnumerator * o_enum = [[NSApp orderedWindows] objectEnumerator];
 
813
            
 
814
            while( ( o_vout_wnd = [o_enum nextObject] ) )
 
815
            {
 
816
                if( [[o_vout_wnd className] isEqualToString: @"VLCWindow"] )
 
817
                {
 
818
                    [o_vout_wnd updateTitle];
 
819
                }
 
820
            }
 
821
            vlc_object_release( (vlc_object_t *)p_vout );
 
822
        }
 
823
        [o_playlist updateRowSelection];
 
824
//        [o_info updateInfo];
 
825
 
 
826
        p_intf->p_sys->b_current_title_update = FALSE;
 
827
    }
 
828
 
 
829
    vlc_mutex_lock( &p_playlist->object_lock );
 
830
 
 
831
#define p_input p_playlist->p_input
 
832
 
 
833
    if( p_intf->p_sys->b_intf_update )
 
834
    {
 
835
        vlc_bool_t b_input = VLC_FALSE;
 
836
        vlc_bool_t b_plmul = VLC_FALSE;
 
837
        vlc_bool_t b_control = VLC_FALSE;
 
838
        vlc_bool_t b_seekable = VLC_FALSE;
 
839
        vlc_bool_t b_chapters = VLC_FALSE;
 
840
 
 
841
        b_plmul = p_playlist->i_size > 1;
 
842
 
 
843
        if( ( b_input = ( p_input != NULL ) ) )
 
844
        {
 
845
            vlc_mutex_lock( &p_input->stream.stream_lock );
 
846
 
 
847
            /* seekable streams */
 
848
            b_seekable = p_input->stream.b_seekable;
 
849
 
 
850
            /* check wether slow/fast motion is possible*/
 
851
            b_control = p_input->stream.b_pace_control; 
 
852
 
 
853
            /* chapters & titles */
 
854
            b_chapters = p_input->stream.i_area_nb > 1; 
 
855
 
 
856
            vlc_mutex_unlock( &p_input->stream.stream_lock );
 
857
        }
 
858
 
 
859
        [o_btn_stop setEnabled: b_input];
 
860
        [o_btn_ff setEnabled: b_seekable];
 
861
        [o_btn_rewind setEnabled: b_seekable];
 
862
        [o_btn_prev setEnabled: (b_plmul || b_chapters)];
 
863
        [o_btn_next setEnabled: (b_plmul || b_chapters)];
 
864
 
 
865
        [o_timeslider setFloatValue: 0.0];
 
866
        [o_timeslider setEnabled: b_seekable];
 
867
        [o_timefield setStringValue: @"0:00:00"];
 
868
 
 
869
        [self manageVolumeSlider];
 
870
        p_intf->p_sys->b_intf_update = VLC_FALSE;
 
871
    }
 
872
 
 
873
    if( p_intf->p_sys->b_fullscreen_update )
 
874
    {
 
875
        vout_thread_t * p_vout;
 
876
        vlc_value_t val;
 
877
 
 
878
        [o_btn_fullscreen setState: ( var_Get( p_playlist, "fullscreen", &val )>=0 && val.b_bool ) ];
 
879
        
 
880
        p_vout = vlc_object_find( p_intf, VLC_OBJECT_VOUT, FIND_ANYWHERE );
 
881
        if( p_vout != NULL )
 
882
        {
 
883
            [o_btn_fullscreen setEnabled: VLC_TRUE];
 
884
            vlc_object_release( p_vout );
 
885
        }
 
886
        else
 
887
        {
 
888
            [o_btn_fullscreen setEnabled: VLC_FALSE];
 
889
        }
 
890
        p_intf->p_sys->b_fullscreen_update = VLC_FALSE;
 
891
    }
 
892
 
 
893
    if( p_intf->p_sys->b_playing && p_input != NULL )
 
894
    {
 
895
        vlc_value_t time;
 
896
        NSString * o_time;
 
897
        mtime_t i_seconds;
 
898
 
 
899
        if( p_input->stream.b_seekable )
 
900
        {
 
901
            vlc_value_t pos;
 
902
            float f_updated;
 
903
            
 
904
            var_Get( p_input, "position", &pos );
 
905
            f_updated = 10000. * pos.f_float;
 
906
 
 
907
            if( f_slider != f_updated )
 
908
            {
 
909
                [o_timeslider setFloatValue: f_updated];
 
910
            }
 
911
        }
 
912
            
 
913
        var_Get( p_input, "time", &time );
 
914
        i_seconds = time.i_time / 1000000;
 
915
        
 
916
        o_time = [NSString stringWithFormat: @"%d:%02d:%02d",
 
917
                        (int) (i_seconds / (60 * 60)),
 
918
                        (int) (i_seconds / 60 % 60),
 
919
                        (int) (i_seconds % 60)];
 
920
        [o_timefield setStringValue: o_time];
 
921
    }
 
922
    if( p_input )
 
923
    {
 
924
        vlc_value_t val;
 
925
        var_Get( p_input, "state", &val );
 
926
 
 
927
        if( val.i_int != PAUSE_S )
 
928
        {
 
929
            p_intf->p_sys->b_play_status = TRUE;
 
930
        }
 
931
        else
 
932
        {
 
933
            p_intf->p_sys->b_play_status = FALSE;
 
934
        }
 
935
        [self playStatusUpdated: p_intf->p_sys->b_play_status];
 
936
    }
 
937
    else
 
938
    {
 
939
        p_intf->p_sys->b_play_status = FALSE;
 
940
        [self playStatusUpdated: p_intf->p_sys->b_play_status];
 
941
        [self setSubmenusEnabled: FALSE];
 
942
    }
 
943
 
 
944
#undef p_input
 
945
 
 
946
    vlc_mutex_unlock( &p_playlist->object_lock );
 
947
    vlc_object_release( p_playlist );
 
948
 
 
949
    [self updateMessageArray];
 
950
 
 
951
    [NSTimer scheduledTimerWithTimeInterval: 0.5
 
952
        target: self selector: @selector(manageIntf:)
 
953
        userInfo: nil repeats: FALSE];
 
954
}
 
955
 
 
956
- (void)setupMenus
 
957
{
 
958
    intf_thread_t * p_intf = [NSApp getIntf];
 
959
    playlist_t *p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, 
 
960
                                                FIND_ANYWHERE );
 
961
    
 
962
    if( p_playlist != NULL )
 
963
    {
 
964
#define p_input p_playlist->p_input
 
965
        if( p_input != NULL )
 
966
        {
 
967
            [o_controls setupVarMenuItem: o_mi_program target: (vlc_object_t *)p_input
 
968
                var: "program" selector: @selector(toggleVar:)];
 
969
            
 
970
            [o_controls setupVarMenuItem: o_mi_title target: (vlc_object_t *)p_input
 
971
                var: "title" selector: @selector(toggleVar:)];
 
972
            
 
973
            [o_controls setupVarMenuItem: o_mi_chapter target: (vlc_object_t *)p_input
 
974
                var: "chapter" selector: @selector(toggleVar:)];
 
975
            
 
976
            [o_controls setupVarMenuItem: o_mi_audiotrack target: (vlc_object_t *)p_input
 
977
                var: "audio-es" selector: @selector(toggleVar:)];
 
978
            
 
979
            [o_controls setupVarMenuItem: o_mi_videotrack target: (vlc_object_t *)p_input
 
980
                var: "video-es" selector: @selector(toggleVar:)];
 
981
            
 
982
            [o_controls setupVarMenuItem: o_mi_subtitle target: (vlc_object_t *)p_input
 
983
                var: "spu-es" selector: @selector(toggleVar:)];
 
984
        
 
985
            aout_instance_t * p_aout = vlc_object_find( p_intf, VLC_OBJECT_AOUT,
 
986
                                                        FIND_ANYWHERE );
 
987
            if ( p_aout != NULL )
 
988
            {
 
989
                [o_controls setupVarMenuItem: o_mi_channels target: (vlc_object_t *)p_aout
 
990
                    var: "audio-channels" selector: @selector(toggleVar:)];
 
991
            
 
992
                [o_controls setupVarMenuItem: o_mi_device target: (vlc_object_t *)p_aout
 
993
                    var: "audio-device" selector: @selector(toggleVar:)];
 
994
                    
 
995
                [o_controls setupVarMenuItem: o_mi_visual target: (vlc_object_t *)p_aout
 
996
                    var: "visual" selector: @selector(toggleVar:)];
 
997
                vlc_object_release( (vlc_object_t *)p_aout );
 
998
            }
 
999
            
 
1000
            vout_thread_t * p_vout = vlc_object_find( p_intf, VLC_OBJECT_VOUT,
 
1001
                                                                FIND_ANYWHERE );
 
1002
            
 
1003
            if ( p_vout != NULL )
 
1004
            {
 
1005
                [o_controls setupVarMenuItem: o_mi_screen target: (vlc_object_t *)p_vout
 
1006
                    var: "video-device" selector: @selector(toggleVar:)];
 
1007
                
 
1008
                [o_controls setupVarMenuItem: o_mi_deinterlace target: (vlc_object_t *)p_vout
 
1009
                    var: "deinterlace" selector: @selector(toggleVar:)];
 
1010
                vlc_object_release( (vlc_object_t *)p_vout );
 
1011
            }
 
1012
        }
 
1013
#undef p_input
 
1014
    }
 
1015
    vlc_object_release( (vlc_object_t *)p_playlist );
 
1016
}
 
1017
 
 
1018
- (void)updateMessageArray
 
1019
{
 
1020
    int i_start, i_stop;
 
1021
    intf_thread_t * p_intf = [NSApp getIntf];
 
1022
    vlc_value_t quiet;
 
1023
 
 
1024
    vlc_mutex_lock( p_intf->p_sys->p_sub->p_lock );
 
1025
    i_stop = *p_intf->p_sys->p_sub->pi_stop;
 
1026
    vlc_mutex_unlock( p_intf->p_sys->p_sub->p_lock );
 
1027
 
 
1028
    if( p_intf->p_sys->p_sub->i_start != i_stop )
 
1029
    {
 
1030
        NSColor *o_white = [NSColor whiteColor];
 
1031
        NSColor *o_red = [NSColor redColor];
 
1032
        NSColor *o_yellow = [NSColor yellowColor];
 
1033
        NSColor *o_gray = [NSColor grayColor];
 
1034
 
 
1035
        NSColor * pp_color[4] = { o_white, o_red, o_yellow, o_gray };
 
1036
        static const char * ppsz_type[4] = { ": ", " error: ",
 
1037
                                             " warning: ", " debug: " };
 
1038
 
 
1039
        for( i_start = p_intf->p_sys->p_sub->i_start;
 
1040
             i_start != i_stop;
 
1041
             i_start = (i_start+1) % VLC_MSG_QSIZE )
 
1042
        {
 
1043
            NSString *o_msg;
 
1044
            NSDictionary *o_attr;
 
1045
            NSAttributedString *o_msg_color;
 
1046
 
 
1047
            int i_type = p_intf->p_sys->p_sub->p_msg[i_start].i_type;
 
1048
 
 
1049
            [o_msg_lock lock];
 
1050
 
 
1051
            if( [o_msg_arr count] + 2 > 400 )
 
1052
            {
 
1053
                unsigned rid[] = { 0, 1 };
 
1054
                [o_msg_arr removeObjectsFromIndices: (unsigned *)&rid
 
1055
                           numIndices: sizeof(rid)/sizeof(rid[0])];
 
1056
            }
 
1057
 
 
1058
            o_attr = [NSDictionary dictionaryWithObject: o_gray
 
1059
                forKey: NSForegroundColorAttributeName];
 
1060
            o_msg = [NSString stringWithFormat: @"%s%s",
 
1061
                p_intf->p_sys->p_sub->p_msg[i_start].psz_module,
 
1062
                ppsz_type[i_type]];
 
1063
            o_msg_color = [[NSAttributedString alloc]
 
1064
                initWithString: o_msg attributes: o_attr];
 
1065
            [o_msg_arr addObject: [o_msg_color autorelease]];
 
1066
 
 
1067
            o_attr = [NSDictionary dictionaryWithObject: pp_color[i_type]
 
1068
                forKey: NSForegroundColorAttributeName];
 
1069
            o_msg = [NSString stringWithFormat: @"%s\n",
 
1070
                p_intf->p_sys->p_sub->p_msg[i_start].psz_msg];
 
1071
            o_msg_color = [[NSAttributedString alloc]
 
1072
                initWithString: o_msg attributes: o_attr];
 
1073
            [o_msg_arr addObject: [o_msg_color autorelease]];
 
1074
 
 
1075
            [o_msg_lock unlock];
 
1076
 
 
1077
            var_Get( p_intf->p_vlc, "verbose", &quiet );
 
1078
 
 
1079
            if( i_type == 1 && quiet.i_int > -1 )
 
1080
            {
 
1081
                NSString *o_my_msg = [NSString stringWithFormat: @"%s: %s\n",
 
1082
                    p_intf->p_sys->p_sub->p_msg[i_start].psz_module,
 
1083
                    p_intf->p_sys->p_sub->p_msg[i_start].psz_msg];
 
1084
 
 
1085
                NSRange s_r = NSMakeRange( [[o_err_msg string] length], 0 );
 
1086
                [o_err_msg setEditable: YES];
 
1087
                [o_err_msg setSelectedRange: s_r];
 
1088
                [o_err_msg insertText: o_my_msg];
 
1089
 
 
1090
                [o_error makeKeyAndOrderFront: self];
 
1091
                [o_err_msg setEditable: NO];
 
1092
            }
 
1093
        }
 
1094
 
 
1095
        vlc_mutex_lock( p_intf->p_sys->p_sub->p_lock );
 
1096
        p_intf->p_sys->p_sub->i_start = i_start;
 
1097
        vlc_mutex_unlock( p_intf->p_sys->p_sub->p_lock );
 
1098
    }
 
1099
}
 
1100
 
 
1101
- (void)playStatusUpdated:(BOOL)b_pause
 
1102
{
 
1103
    if( b_pause )
 
1104
    {
 
1105
        [o_btn_play setImage: o_img_pause];
 
1106
        [o_btn_play setAlternateImage: o_img_pause_pressed];
 
1107
        [o_btn_play setToolTip: _NS("Pause")];
 
1108
        [o_mi_play setTitle: _NS("Pause")];
 
1109
        [o_dmi_play setTitle: _NS("Pause")];
 
1110
    }
 
1111
    else
 
1112
    {
 
1113
        [o_btn_play setImage: o_img_play];
 
1114
        [o_btn_play setAlternateImage: o_img_play_pressed];
 
1115
        [o_btn_play setToolTip: _NS("Play")];
 
1116
        [o_mi_play setTitle: _NS("Play")];
 
1117
        [o_dmi_play setTitle: _NS("Play")];
 
1118
    }
 
1119
}
 
1120
 
 
1121
- (void)setSubmenusEnabled:(BOOL)b_enabled
 
1122
{
 
1123
    [o_mi_program setEnabled: b_enabled];
 
1124
    [o_mi_title setEnabled: b_enabled];
 
1125
    [o_mi_chapter setEnabled: b_enabled];
 
1126
    [o_mi_audiotrack setEnabled: b_enabled];
 
1127
    [o_mi_visual setEnabled: b_enabled];
 
1128
    [o_mi_videotrack setEnabled: b_enabled];
 
1129
    [o_mi_subtitle setEnabled: b_enabled];
 
1130
    [o_mi_channels setEnabled: b_enabled];
 
1131
    [o_mi_deinterlace setEnabled: b_enabled];
 
1132
    [o_mi_device setEnabled: b_enabled];
 
1133
    [o_mi_screen setEnabled: b_enabled];
 
1134
}
 
1135
 
 
1136
- (void)manageVolumeSlider
 
1137
{
 
1138
    audio_volume_t i_volume;
 
1139
    intf_thread_t * p_intf = [NSApp getIntf];
 
1140
 
 
1141
    aout_VolumeGet( p_intf, &i_volume );
 
1142
 
 
1143
    [o_volumeslider setFloatValue: (float)i_volume / AOUT_VOLUME_STEP]; 
 
1144
    [o_volumeslider setEnabled: TRUE];
 
1145
 
 
1146
    p_intf->p_sys->b_mute = ( i_volume == 0 );
 
1147
}
 
1148
 
 
1149
- (IBAction)timesliderUpdate:(id)sender
 
1150
{
 
1151
    intf_thread_t * p_intf;
 
1152
    input_thread_t * p_input;
 
1153
    float f_updated;
 
1154
 
 
1155
    switch( [[NSApp currentEvent] type] )
 
1156
    {
 
1157
        case NSLeftMouseUp:
 
1158
        case NSLeftMouseDown:
 
1159
        case NSLeftMouseDragged:
 
1160
            f_updated = [sender floatValue];
 
1161
            break;
 
1162
 
 
1163
        default:
 
1164
            return;
 
1165
    }
 
1166
 
 
1167
    p_intf = [NSApp getIntf];
 
1168
    p_input = vlc_object_find( p_intf, VLC_OBJECT_INPUT,
 
1169
                                            FIND_ANYWHERE );
 
1170
 
 
1171
    if( p_input != NULL )
 
1172
    {
 
1173
        vlc_value_t time;
 
1174
        mtime_t i_seconds;
 
1175
        NSString * o_time;
 
1176
 
 
1177
        if( p_input->stream.b_seekable )
 
1178
        {
 
1179
                vlc_value_t pos;
 
1180
                pos.f_float = f_updated / 10000.;
 
1181
                if( f_slider != f_updated )
 
1182
                {
 
1183
                    var_Set( p_input, "position", pos );
 
1184
                    [o_timeslider setFloatValue: f_updated];
 
1185
                }
 
1186
        }
 
1187
            
 
1188
        var_Get( p_input, "time", &time );
 
1189
        i_seconds = time.i_time / 1000000;
 
1190
        
 
1191
        o_time = [NSString stringWithFormat: @"%d:%02d:%02d",
 
1192
                        (int) (i_seconds / (60 * 60)),
 
1193
                        (int) (i_seconds / 60 % 60),
 
1194
                        (int) (i_seconds % 60)];
 
1195
        [o_timefield setStringValue: o_time];
 
1196
        vlc_object_release( p_input );
 
1197
    }
 
1198
}
 
1199
 
 
1200
- (void)terminate
 
1201
{
 
1202
    NSEvent * o_event;
 
1203
    playlist_t * p_playlist;
 
1204
    vout_thread_t * p_vout;
 
1205
    intf_thread_t * p_intf = [NSApp getIntf];
 
1206
 
 
1207
    /* Stop playback */
 
1208
    if( ( p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
 
1209
                                        FIND_ANYWHERE ) ) )
 
1210
    {
 
1211
        playlist_Stop( p_playlist );
 
1212
        vlc_object_release( p_playlist );
 
1213
    }
 
1214
 
 
1215
    /* FIXME - Wait here until all vouts are terminated because
 
1216
       libvlc's VLC_Stop destroys interfaces before vouts, which isn't
 
1217
       good on OS X. We definitly need a cleaner way to handle this,
 
1218
       but this may hopefully be good enough for now.
 
1219
         -- titer 2003/11/22 */
 
1220
    while( ( p_vout = vlc_object_find( p_intf, VLC_OBJECT_VOUT,
 
1221
                                       FIND_ANYWHERE ) ) )
 
1222
    {
 
1223
        vlc_object_release( p_vout );
 
1224
        msleep( 100000 );
 
1225
    }
 
1226
    msleep( 500000 );
 
1227
 
 
1228
    if( o_img_pause_pressed != nil )
 
1229
    {
 
1230
        [o_img_pause_pressed release];
 
1231
        o_img_pause_pressed = nil;
 
1232
    }
 
1233
    
 
1234
    if( o_img_pause_pressed != nil )
 
1235
    {
 
1236
        [o_img_pause_pressed release];
 
1237
        o_img_pause_pressed = nil;
 
1238
    }
 
1239
    
 
1240
    if( o_img_pause != nil )
 
1241
    {
 
1242
        [o_img_pause release];
 
1243
        o_img_pause = nil;
 
1244
    }
 
1245
 
 
1246
    if( o_img_play != nil )
 
1247
    {
 
1248
        [o_img_play release];
 
1249
        o_img_play = nil;
 
1250
    }
 
1251
 
 
1252
    if( o_msg_arr != nil )
 
1253
    {
 
1254
        [o_msg_arr removeAllObjects];
 
1255
        [o_msg_arr release];
 
1256
        o_msg_arr = nil;
 
1257
    }
 
1258
 
 
1259
    if( o_msg_lock != nil )
 
1260
    {
 
1261
        [o_msg_lock release];
 
1262
        o_msg_lock = nil;
 
1263
    }
 
1264
 
 
1265
    [NSApp terminate: nil];
 
1266
    [NSApp stop: nil];
 
1267
 
 
1268
    /* write cached user defaults to disk */
 
1269
    [[NSUserDefaults standardUserDefaults] synchronize];
 
1270
 
 
1271
    /* send a dummy event to break out of the event loop */
 
1272
    o_event = [NSEvent mouseEventWithType: NSLeftMouseDown
 
1273
                location: NSMakePoint( 1, 1 ) modifierFlags: 0
 
1274
                timestamp: 1 windowNumber: [[NSApp mainWindow] windowNumber]
 
1275
                context: [NSGraphicsContext currentContext] eventNumber: 1
 
1276
                clickCount: 1 pressure: 0.0];
 
1277
    [NSApp postEvent: o_event atStart: YES];
 
1278
}
 
1279
 
 
1280
- (IBAction)clearRecentItems:(id)sender
 
1281
{
 
1282
    [[NSDocumentController sharedDocumentController]
 
1283
                          clearRecentDocuments: nil];
 
1284
}
 
1285
 
 
1286
- (void)openRecentItem:(id)sender
 
1287
{
 
1288
    [self application: nil openFile: [sender title]]; 
 
1289
}
 
1290
 
 
1291
- (IBAction)viewPreferences:(id)sender
 
1292
{
 
1293
    [o_prefs showPrefs];
 
1294
}
 
1295
 
 
1296
- (IBAction)closeError:(id)sender
 
1297
{
 
1298
    vlc_value_t val;
 
1299
    intf_thread_t * p_intf = [NSApp getIntf];
 
1300
    
 
1301
    if( [o_err_ckbk_surpress state] == NSOnState )
 
1302
    {
 
1303
        val.i_int = -1;
 
1304
        var_Set( p_intf->p_vlc, "verbose", val );
 
1305
    }
 
1306
    [o_err_msg setString: @""];
 
1307
    [o_error performClose: self];
 
1308
}
 
1309
 
 
1310
- (IBAction)openReadMe:(id)sender
 
1311
{
 
1312
    NSString * o_path = [[NSBundle mainBundle] 
 
1313
        pathForResource: @"README.MacOSX" ofType: @"rtf"]; 
 
1314
 
 
1315
    [[NSWorkspace sharedWorkspace] openFile: o_path 
 
1316
                                   withApplication: @"TextEdit"];
 
1317
}
 
1318
 
 
1319
- (IBAction)openDocumentation:(id)sender
 
1320
{
 
1321
    NSURL * o_url = [NSURL URLWithString: 
 
1322
        @"http://www.videolan.org/doc/"];
 
1323
 
 
1324
    [[NSWorkspace sharedWorkspace] openURL: o_url];
 
1325
}
 
1326
 
 
1327
- (IBAction)reportABug:(id)sender
 
1328
{
 
1329
    NSURL * o_url = [NSURL URLWithString: 
 
1330
        @"http://www.videolan.org/support/bug-reporting.html"];
 
1331
 
 
1332
    [[NSWorkspace sharedWorkspace] openURL: o_url];
 
1333
}
 
1334
 
 
1335
- (IBAction)openWebsite:(id)sender
 
1336
{
 
1337
    NSURL * o_url = [NSURL URLWithString: @"http://www.videolan.org/"];
 
1338
 
 
1339
    [[NSWorkspace sharedWorkspace] openURL: o_url];
 
1340
}
 
1341
 
 
1342
- (IBAction)openLicense:(id)sender
 
1343
{
 
1344
    NSString * o_path = [[NSBundle mainBundle] 
 
1345
        pathForResource: @"COPYING" ofType: nil];
 
1346
 
 
1347
    [[NSWorkspace sharedWorkspace] openFile: o_path 
 
1348
                                   withApplication: @"TextEdit"];
 
1349
}
 
1350
 
 
1351
- (IBAction)openCrashLog:(id)sender
 
1352
{
 
1353
    NSString * o_path = [@"~/Library/Logs/CrashReporter/VLC.crash.log"
 
1354
                                    stringByExpandingTildeInPath]; 
 
1355
 
 
1356
    
 
1357
    if ( [[NSFileManager defaultManager] fileExistsAtPath: o_path ] )
 
1358
    {
 
1359
        [[NSWorkspace sharedWorkspace] openFile: o_path 
 
1360
                                    withApplication: @"Console"];
 
1361
    }
 
1362
    else
 
1363
    {
 
1364
        NSBeginInformationalAlertSheet(_NS("No CrashLog found"), @"Continue", nil, nil, o_msgs_panel, self, NULL, NULL, nil, _NS("Either you are running Mac OS X pre 10.2 or you haven't experienced any heavy crashes yet.") );
 
1365
 
 
1366
    }
 
1367
}
 
1368
 
 
1369
- (void)windowDidBecomeKey:(NSNotification *)o_notification
 
1370
{
 
1371
    if( [o_notification object] == o_msgs_panel )
 
1372
    {
 
1373
        id o_msg;
 
1374
        NSEnumerator * o_enum;
 
1375
 
 
1376
        [o_messages setString: @""]; 
 
1377
 
 
1378
        [o_msg_lock lock];
 
1379
 
 
1380
        o_enum = [o_msg_arr objectEnumerator];
 
1381
 
 
1382
        while( ( o_msg = [o_enum nextObject] ) != nil )
 
1383
        {
 
1384
            [o_messages insertText: o_msg];
 
1385
        }
 
1386
 
 
1387
        [o_msg_lock unlock];
 
1388
    }
 
1389
}
 
1390
 
 
1391
@end
 
1392
 
 
1393
@implementation VLCMain (NSMenuValidation)
 
1394
 
 
1395
- (BOOL)validateMenuItem:(NSMenuItem *)o_mi
 
1396
{
 
1397
    NSString *o_title = [o_mi title];
 
1398
    BOOL bEnabled = TRUE;
 
1399
 
 
1400
    if( [o_title isEqualToString: _NS("License")] )
 
1401
    {
 
1402
        /* we need to do this only once */
 
1403
        [self setupMenus];
 
1404
    }
 
1405
 
 
1406
    /* Recent Items Menu */
 
1407
    if( [o_title isEqualToString: _NS("Clear Menu")] )
 
1408
    {
 
1409
        NSMenu * o_menu = [o_mi_open_recent submenu];
 
1410
        int i_nb_items = [o_menu numberOfItems];
 
1411
        NSArray * o_docs = [[NSDocumentController sharedDocumentController]
 
1412
                                                       recentDocumentURLs];
 
1413
        UInt32 i_nb_docs = [o_docs count];
 
1414
 
 
1415
        if( i_nb_items > 1 )
 
1416
        {
 
1417
            while( --i_nb_items )
 
1418
            {
 
1419
                [o_menu removeItemAtIndex: 0];
 
1420
            }
 
1421
        }
 
1422
 
 
1423
        if( i_nb_docs > 0 )
 
1424
        {
 
1425
            NSURL * o_url;
 
1426
            NSString * o_doc;
 
1427
 
 
1428
            [o_menu insertItem: [NSMenuItem separatorItem] atIndex: 0];
 
1429
 
 
1430
            while( TRUE )
 
1431
            {
 
1432
                i_nb_docs--;
 
1433
 
 
1434
                o_url = [o_docs objectAtIndex: i_nb_docs];
 
1435
 
 
1436
                if( [o_url isFileURL] )
 
1437
                {
 
1438
                    o_doc = [o_url path];
 
1439
                }
 
1440
                else
 
1441
                {
 
1442
                    o_doc = [o_url absoluteString];
 
1443
                }
 
1444
 
 
1445
                [o_menu insertItemWithTitle: o_doc
 
1446
                    action: @selector(openRecentItem:)
 
1447
                    keyEquivalent: @"" atIndex: 0]; 
 
1448
 
 
1449
                if( i_nb_docs == 0 )
 
1450
                {
 
1451
                    break;
 
1452
                }
 
1453
            } 
 
1454
        }
 
1455
        else
 
1456
        {
 
1457
            bEnabled = FALSE;
 
1458
        }
 
1459
    }
 
1460
    return( bEnabled );
 
1461
}
 
1462
 
 
1463
@end
 
1464
 
 
1465
@implementation VLCMain (Internal)
 
1466
 
 
1467
- (void)handlePortMessage:(NSPortMessage *)o_msg
 
1468
{
 
1469
    id ** val;
 
1470
    NSData * o_data;
 
1471
    NSValue * o_value;
 
1472
    NSInvocation * o_inv;
 
1473
    NSConditionLock * o_lock;
 
1474
 
 
1475
    o_data = [[o_msg components] lastObject];
 
1476
    o_inv = *((NSInvocation **)[o_data bytes]); 
 
1477
    [o_inv getArgument: &o_value atIndex: 2];
 
1478
    val = (id **)[o_value pointerValue];
 
1479
    [o_inv setArgument: val[1] atIndex: 2];
 
1480
    o_lock = *(val[0]);
 
1481
 
 
1482
    [o_lock lock];
 
1483
    [o_inv invoke];
 
1484
    [o_lock unlockWithCondition: 1];
 
1485
}
 
1486
 
 
1487
@end