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

27
#import "CompatibilityFixes.h"
28
#import "MainWindow.h"
29
30
31
32
#import "intf.h"
#import "CoreInteraction.h"
#import "AudioEffects.h"
#import "MainMenu.h"
33
#import "open.h"
34
#import "controls.h" // TODO: remove me
35
#import "playlist.h"
36
#import "SideBarItem.h"
37
#import <math.h>
38
39
#import <vlc_playlist.h>
#import <vlc_aout_intf.h>
40
41
#import <vlc_url.h>
#import <vlc_strings.h>
42
#import <vlc_services_discovery.h>
43
#import <vlc_aout_intf.h>
44

45
46
47
#import "ControlsBar.h"


48
49
50
51
52
53
54
@interface VLCMainWindow ()
- (void)resizePlaylistAfterCollapse;
- (void)makeSplitViewVisible;
- (void)makeSplitViewHidden;

@end

55
@implementation VLCMainWindow
56
57
static const float f_min_video_height = 70.0;

58
static VLCMainWindow *_o_sharedInstance = nil;
59

60
61
62
63
64
65
66
67
68
69
+ (VLCMainWindow *)sharedInstance
{
    return _o_sharedInstance ? _o_sharedInstance : [[self alloc] init];
}

#pragma mark -
#pragma mark Initialization

- (id)init
{
70
    if (_o_sharedInstance) {
71
72
        [self dealloc];
        return _o_sharedInstance;
73
    } else
74
75
76
77
78
79
80
81
        _o_sharedInstance = [super init];

    return _o_sharedInstance;
}

- (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)styleMask
                  backing:(NSBackingStoreType)backingType defer:(BOOL)flag
{
82
83
    self = [super initWithContentRect:contentRect styleMask:styleMask
                              backing:backingType defer:flag];
84
    _o_sharedInstance = self;
85
86
87
88
89
90

    [[VLCMain sharedInstance] updateTogglePlaylistState];

    return self;
}

91
92
93
94
95
- (BOOL)isEvent:(NSEvent *)o_event forKey:(const char *)keyString
{
    char *key;
    NSString *o_key;

96
    key = config_GetPsz(VLCIntf, keyString);
97
    o_key = [NSString stringWithFormat:@"%s", key];
98
    FREENULL(key);
99

100
    unsigned int i_keyModifiers = [[VLCStringUtility sharedInstance] VLCModifiersToCocoa:o_key];
101

102
103
    NSString * characters = [o_event charactersIgnoringModifiers];
    if ([characters length] > 0) {
104
        return [[characters lowercaseString] isEqualToString: [[VLCStringUtility sharedInstance] VLCKeyToString: o_key]] &&
105
106
107
108
109
110
                (i_keyModifiers & NSShiftKeyMask)     == ([o_event modifierFlags] & NSShiftKeyMask) &&
                (i_keyModifiers & NSControlKeyMask)   == ([o_event modifierFlags] & NSControlKeyMask) &&
                (i_keyModifiers & NSAlternateKeyMask) == ([o_event modifierFlags] & NSAlternateKeyMask) &&
                (i_keyModifiers & NSCommandKeyMask)   == ([o_event modifierFlags] & NSCommandKeyMask);
    }
    return NO;
111
112
}

113
114
- (BOOL)performKeyEquivalent:(NSEvent *)o_event
{
115
    BOOL b_force = NO;
116
    // these are key events which should be handled by vlc core, but are attached to a main menu item
117
    if (![self isEvent: o_event forKey: "key-vol-up"] &&
118
        ![self isEvent: o_event forKey: "key-vol-down"] &&
119
        ![self isEvent: o_event forKey: "key-vol-mute"]) {
120
121
        /* We indeed want to prioritize some Cocoa key equivalent against libvlc,
         so we perform the menu equivalent now. */
122
        if ([[NSApp mainMenu] performKeyEquivalent:o_event])
123
124
            return TRUE;
    }
125
126
    else
        b_force = YES;
127

128
    return [[VLCMain sharedInstance] hasDefinedShortcutKey:o_event force:b_force] ||
129
           [(VLCControls *)[[VLCMain sharedInstance] controls] keyEvent:o_event];
130
131
132
133
}

- (void)dealloc
{
134
135
136
    if (b_dark_interface)
        [o_color_backdrop release];

137
    [[NSNotificationCenter defaultCenter] removeObserver: self];
138
    [o_sidebaritems release];
139

140
    if (o_extra_video_window) {
141
        [o_extra_video_window release];
142
143
        o_extra_video_window = nil;
    }
144

145
146
147
148
149
    [super dealloc];
}

- (void)awakeFromNib
{
150
    BOOL b_splitviewShouldBeHidden = NO;
151

152
    /* setup the styled interface */
153
    b_nativeFullscreenMode = NO;
154
#ifdef MAC_OS_X_VERSION_10_7
155
    if (!OSX_SNOW_LEOPARD)
156
        b_nativeFullscreenMode = var_InheritBool(VLCIntf, "macosx-nativefullscreenmode");
157
#endif
158
    t_hide_mouse_timer = nil;
159
    [o_detached_video_window setDelegate: self];
160
    [self useOptimizedDrawing: YES];
161
    
162
    [[o_search_fld cell] setPlaceholderString: _NS("Search")];
163
    [[o_search_fld cell] accessibilitySetOverrideValue:_NS("Enter a term to search the playlist. Results will be selected in the table.") forAttribute:NSAccessibilityDescriptionAttribute];
164

165
    [o_dropzone_btn setTitle: _NS("Open media...")];
166
    [[o_dropzone_btn cell] accessibilitySetOverrideValue:_NS("Click to open an advanced dialog to select the media to play. You can also drop files here to play.") forAttribute:NSAccessibilityDescriptionAttribute];
167
    [o_dropzone_lbl setStringValue: _NS("Drop media here")];
168

169
170
    [o_podcast_add_btn setTitle: _NS("Subscribe")];
    [o_podcast_remove_btn setTitle: _NS("Unsubscribe")];
171
172
173
174
    [o_podcast_subscribe_title_lbl setStringValue: _NS("Subscribe to a podcast")];
    [o_podcast_subscribe_subtitle_lbl setStringValue: _NS("Enter URL of the podcast to subscribe to:")];
    [o_podcast_subscribe_cancel_btn setTitle: _NS("Cancel")];
    [o_podcast_subscribe_ok_btn setTitle: _NS("Subscribe")];
175
176
177
178
    [o_podcast_unsubscribe_title_lbl setStringValue: _NS("Unsubscribe from a podcast")];
    [o_podcast_unsubscribe_subtitle_lbl setStringValue: _NS("Select the podcast you would like to unsubscribe from:")];
    [o_podcast_unsubscribe_ok_btn setTitle: _NS("Unsubscribe")];
    [o_podcast_unsubscribe_cancel_btn setTitle: _NS("Cancel")];
179

180
    /* interface builder action */
181
    float f_threshold_height = f_min_video_height + [[o_controls_bar bottomBarView] frame].size.height;
182
    if (b_dark_interface)
183
        f_threshold_height += [o_titlebar_view frame].size.height;
184
    if ([[self contentView] frame].size.height < f_threshold_height)
185
        b_splitviewShouldBeHidden = YES;
186

187
188
    [self setDelegate: self];
    [self setExcludedFromWindowsMenu: YES];
189
    [self setAcceptsMouseMovedEvents: YES];
190
    // Set that here as IB seems to be buggy
191
    if (b_dark_interface) {
192
        [self setContentMinSize:NSMakeSize(604., 288. + [o_titlebar_view frame].size.height)];
193
        [o_detached_video_window setContentMinSize: NSMakeSize(363., f_min_video_height + [[[o_detached_video_window controlsBar] bottomBarView] frame].size.height + [o_titlebar_view frame].size.height)];
194
    } else {
195
        [self setContentMinSize:NSMakeSize(604., 288.)];
196
        [o_detached_video_window setContentMinSize: NSMakeSize(363., f_min_video_height + [[[o_detached_video_window controlsBar] bottomBarView] frame].size.height)];
197
    }
198

199
    [self setTitle: _NS("VLC media player")];
200

201
    b_dropzone_active = YES;
202
203
    o_temp_view = [[NSView alloc] init];
    [o_temp_view setAutoresizingMask:NSViewHeightSizable | NSViewWidthSizable];
204
    [o_dropzone_view setFrame: [o_playlist_table frame]];
205
    [o_left_split_view setFrame: [o_sidebar_view frame]];
206
    
207
    if (b_nativeFullscreenMode) {
208
        [self setCollectionBehavior: NSWindowCollectionBehaviorFullScreenPrimary];
209
    } else {
210
        [o_titlebar_view setFullscreenButtonHidden: YES];
211
    }
212

213
    if (!OSX_SNOW_LEOPARD) {
214
215
216
217
218
219
220
        /* the default small size of the search field is slightly different on Lion, let's work-around that */
        NSRect frame;
        frame = [o_search_fld frame];
        frame.origin.y = frame.origin.y + 2.0;
        frame.size.height = frame.size.height - 1.0;
        [o_search_fld setFrame: frame];
    }
221

222
223
224
225
    /* create the sidebar */
    o_sidebaritems = [[NSMutableArray alloc] init];
    SideBarItem *libraryItem = [SideBarItem itemWithTitle:_NS("LIBRARY") identifier:@"library"];
    SideBarItem *playlistItem = [SideBarItem itemWithTitle:_NS("Playlist") identifier:@"playlist"];
226
    [playlistItem setIcon: [NSImage imageNamed:@"sidebar-playlist"]];
227
228
    SideBarItem *medialibraryItem = [SideBarItem itemWithTitle:_NS("Media Library") identifier:@"medialibrary"];
    [medialibraryItem setIcon: [NSImage imageNamed:@"sidebar-playlist"]];
229
230
231
232
233
234
235
236
    SideBarItem *mycompItem = [SideBarItem itemWithTitle:_NS("MY COMPUTER") identifier:@"mycomputer"];
    SideBarItem *devicesItem = [SideBarItem itemWithTitle:_NS("DEVICES") identifier:@"devices"];
    SideBarItem *lanItem = [SideBarItem itemWithTitle:_NS("LOCAL NETWORK") identifier:@"localnetwork"];
    SideBarItem *internetItem = [SideBarItem itemWithTitle:_NS("INTERNET") identifier:@"internet"];

    /* SD subnodes, inspired by the Qt4 intf */
    char **ppsz_longnames;
    int *p_categories;
237
    char **ppsz_names = vlc_sd_GetNames(pl_Get(VLCIntf), &ppsz_longnames, &p_categories);
238
    if (!ppsz_names)
239
        msg_Err(VLCIntf, "no sd item found"); //TODO
240
241
242
243
244
245
    char **ppsz_name = ppsz_names, **ppsz_longname = ppsz_longnames;
    int *p_category = p_categories;
    NSMutableArray *internetItems = [[NSMutableArray alloc] init];
    NSMutableArray *devicesItems = [[NSMutableArray alloc] init];
    NSMutableArray *lanItems = [[NSMutableArray alloc] init];
    NSMutableArray *mycompItems = [[NSMutableArray alloc] init];
246
    NSString *o_identifier;
247
    for (; *ppsz_name; ppsz_name++, ppsz_longname++, p_category++) {
248
        o_identifier = [NSString stringWithCString: *ppsz_name encoding: NSUTF8StringEncoding];
249
250
        switch (*p_category) {
            case SD_CAT_INTERNET:
251
                    [internetItems addObject: [SideBarItem itemWithTitle: _NS(*ppsz_longname) identifier: o_identifier]];
252
                    if (!strncmp(*ppsz_name, "podcast", 7))
253
                        [[internetItems lastObject] setIcon: [NSImage imageNamed:@"sidebar-podcast"]];
254
255
                    else
                        [[internetItems lastObject] setIcon: [NSImage imageNamed:@"NSApplicationIcon"]];
256
                    [[internetItems lastObject] setSdtype: SD_CAT_INTERNET];
257
                    [[internetItems lastObject] setUntranslatedTitle: [NSString stringWithUTF8String: *ppsz_longname]];
258
259
                break;
            case SD_CAT_DEVICES:
260
                    [devicesItems addObject: [SideBarItem itemWithTitle: _NS(*ppsz_longname) identifier: o_identifier]];
261
                    [[devicesItems lastObject] setIcon: [NSImage imageNamed:@"NSApplicationIcon"]];
262
                    [[devicesItems lastObject] setSdtype: SD_CAT_DEVICES];
263
                    [[devicesItems lastObject] setUntranslatedTitle: [NSString stringWithUTF8String: *ppsz_longname]];
264
265
                break;
            case SD_CAT_LAN:
266
                    [lanItems addObject: [SideBarItem itemWithTitle: _NS(*ppsz_longname) identifier: o_identifier]];
267
                    [[lanItems lastObject] setIcon: [NSImage imageNamed:@"sidebar-local"]];
268
                    [[lanItems lastObject] setSdtype: SD_CAT_LAN];
269
                    [[lanItems lastObject] setUntranslatedTitle: [NSString stringWithUTF8String: *ppsz_longname]];
270
271
                break;
            case SD_CAT_MYCOMPUTER:
272
                    [mycompItems addObject: [SideBarItem itemWithTitle: _NS(*ppsz_longname) identifier: o_identifier]];
273
                    if (!strncmp(*ppsz_name, "video_dir", 9))
274
                        [[mycompItems lastObject] setIcon: [NSImage imageNamed:@"sidebar-movie"]];
275
                    else if (!strncmp(*ppsz_name, "audio_dir", 9))
276
                        [[mycompItems lastObject] setIcon: [NSImage imageNamed:@"sidebar-music"]];
277
                    else if (!strncmp(*ppsz_name, "picture_dir", 11))
278
                        [[mycompItems lastObject] setIcon: [NSImage imageNamed:@"sidebar-pictures"]];
279
280
                    else
                        [[mycompItems lastObject] setIcon: [NSImage imageNamed:@"NSApplicationIcon"]];
281
                    [[mycompItems lastObject] setUntranslatedTitle: [NSString stringWithUTF8String: *ppsz_longname]];
282
                    [[mycompItems lastObject] setSdtype: SD_CAT_MYCOMPUTER];
283
284
                break;
            default:
285
                msg_Warn(VLCIntf, "unknown SD type found, skipping (%s)", *ppsz_name);
286
287
288
                break;
        }

289
290
        free(*ppsz_name);
        free(*ppsz_longname);
291
292
293
294
295
296
297
298
299
    }
    [mycompItem setChildren: [NSArray arrayWithArray: mycompItems]];
    [devicesItem setChildren: [NSArray arrayWithArray: devicesItems]];
    [lanItem setChildren: [NSArray arrayWithArray: lanItems]];
    [internetItem setChildren: [NSArray arrayWithArray: internetItems]];
    [mycompItems release];
    [devicesItems release];
    [lanItems release];
    [internetItems release];
300
301
302
    free(ppsz_names);
    free(ppsz_longnames);
    free(p_categories);
303

304
    [libraryItem setChildren: [NSArray arrayWithObjects: playlistItem, medialibraryItem, nil]];
305
306
307
308
309
310
311
312
313
314
315
    [o_sidebaritems addObject: libraryItem];
    if ([mycompItem hasChildren])
        [o_sidebaritems addObject: mycompItem];
    if ([devicesItem hasChildren])
        [o_sidebaritems addObject: devicesItem];
    if ([lanItem hasChildren])
        [o_sidebaritems addObject: lanItem];
    if ([internetItem hasChildren])
        [o_sidebaritems addObject: internetItem];

    [o_sidebar_view reloadData];
316
    [o_sidebar_view selectRowIndexes:[NSIndexSet indexSetWithIndex:1] byExtendingSelection:NO];
317
318
    [o_sidebar_view setDropItem:playlistItem dropChildIndex:NSOutlineViewDropOnItemIndex];
    [o_sidebar_view registerForDraggedTypes:[NSArray arrayWithObjects: NSFilenamesPboardType, @"VLCPlaylistItemPboardType", nil]];
319

320
321
322
323
324
    [o_sidebar_view setAutosaveName:@"mainwindow-sidebar"];
    [(PXSourceList *)o_sidebar_view setDataSource:self];
    [o_sidebar_view setDelegate:self];
    [o_sidebar_view setAutosaveExpandedItems:YES];

325
326
327
328
    [o_sidebar_view expandItem: libraryItem expandChildren: YES];

    /* make sure we display the desired default appearance when VLC launches for the first time */
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
329
    if (![defaults objectForKey:@"VLCFirstRun"]) {
330
331
332
333
334
335
336
        [defaults setObject:[NSDate date] forKey:@"VLCFirstRun"];

        NSUInteger i_sidebaritem_count = [o_sidebaritems count];
        for (NSUInteger x = 0; x < i_sidebaritem_count; x++)
            [o_sidebar_view expandItem: [o_sidebaritems objectAtIndex: x] expandChildren: YES];
    }

337
    if (b_dark_interface) {
338
339
340
        [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(windowResizedOrMoved:) name: NSWindowDidResizeNotification object: nil];
        [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(windowResizedOrMoved:) name: NSWindowDidMoveNotification object: nil];

341
342
        [self setBackgroundColor: [NSColor clearColor]];
        [self setOpaque: NO];
343
344
        [self display];
        [self setHasShadow:NO];
345
        [self setHasShadow:YES];
346

347
        NSRect winrect = [self frame];
348
349
        CGFloat f_titleBarHeight = [o_titlebar_view frame].size.height;

350
351
        [o_titlebar_view setFrame: NSMakeRect(0, winrect.size.height - f_titleBarHeight,
                                              winrect.size.width, f_titleBarHeight)];
352
353
        [[self contentView] addSubview: o_titlebar_view positioned: NSWindowAbove relativeTo: o_split_view];

354
        if (winrect.size.height > 100) {
355
356
357
            [self setFrame: winrect display:YES animate:YES];
            previousSavedFrame = winrect;
        }
358
359
360
361
362

        winrect = [o_split_view frame];
        winrect.size.height = winrect.size.height - f_titleBarHeight;
        [o_split_view setFrame: winrect];
        [o_video_view setFrame: winrect];
363

364
365
366
        o_color_backdrop = [[VLCColorView alloc] initWithFrame: [o_split_view frame]];
        [[self contentView] addSubview: o_color_backdrop positioned: NSWindowBelow relativeTo: o_split_view];
        [o_color_backdrop setAutoresizingMask:NSViewHeightSizable | NSViewWidthSizable];
367
        
368
    } else {
369
        [o_video_view setFrame: [o_split_view frame]];
370
371
372
        [o_playlist_table setBorderType: NSNoBorder];
        [o_sidebar_scrollview setBorderType: NSNoBorder];
    }
373

374
    [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(someWindowWillClose:) name: NSWindowWillCloseNotification object: nil];
375
    [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(someWindowWillMiniaturize:) name: NSWindowWillMiniaturizeNotification object:nil];
376
    [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(applicationWillTerminate:) name: NSApplicationWillTerminateNotification object: nil];
377

378
    [o_split_view setAutosaveName:@"10thanniversary-splitview"];
379
    if (b_splitviewShouldBeHidden) {
380
        [self hideSplitView];
381
        i_lastSplitViewHeight = 300;
382
    }
383
384

    /* sanity check for the window size */
385
    NSRect frame = [self frame];
386
387
388
389
390
    NSSize screenSize = [[self screen] frame].size;
    if (screenSize.width <= frame.size.width || screenSize.height <= frame.size.height) {
        nativeVideoSize = screenSize;
        [self resizeWindow];
    }
391
392
}

393
#pragma mark -
394

395
- (VLCMainWindowControlsBar *)controlsBar;
396
{
397
    return (VLCMainWindowControlsBar *)o_controls_bar;
398
399
}

400
401
402
- (void)resizePlaylistAfterCollapse
{
    NSRect plrect;
403
    plrect = [o_playlist_table frame];
404
    plrect.size.height = i_lastSplitViewHeight - 20.0; // actual pl top bar height, which differs from its frame
405
    [[o_playlist_table animator] setFrame: plrect];
406
407
408

    NSRect rightSplitRect;
    rightSplitRect = [o_right_split_view frame];
409
    plrect = [o_dropzone_box frame];
410
411
    plrect.origin.x = (rightSplitRect.size.width - plrect.size.width) / 2;
    plrect.origin.y = (rightSplitRect.size.height - plrect.size.height) / 2;
412
    [[o_dropzone_box animator] setFrame: plrect];
413
414
}

415
416
- (void)makeSplitViewVisible
{
417
418
    if (b_dark_interface)
        [self setContentMinSize: NSMakeSize(604., 288. + [o_titlebar_view frame].size.height)];
419
    else
420
        [self setContentMinSize: NSMakeSize(604., 288.)];
421
422
423

    NSRect old_frame = [self frame];
    float newHeight = [self minSize].height;
424
    if (old_frame.size.height < newHeight) {
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
        NSRect new_frame = old_frame;
        new_frame.origin.y = old_frame.origin.y + old_frame.size.height - newHeight;
        new_frame.size.height = newHeight;

        [[self animator] setFrame: new_frame display: YES animate: YES];
    }

    [o_video_view setHidden: YES];
    [o_split_view setHidden: NO];
    [self makeFirstResponder: nil];

}

- (void)makeSplitViewHidden
{
440
441
    if (b_dark_interface)
        [self setContentMinSize: NSMakeSize(604., f_min_video_height + [o_titlebar_view frame].size.height)];
442
    else
443
        [self setContentMinSize: NSMakeSize(604., f_min_video_height)];
444
445
446

    [o_split_view setHidden: YES];
    [o_video_view setHidden: NO];
447

448
    if ([[o_video_view subviews] count] > 0)
449
        [self makeFirstResponder: [[o_video_view subviews] objectAtIndex:0]];
450
451
}

452
// only exception for an controls bar button action
453
454
- (IBAction)togglePlaylist:(id)sender
{
455
    if (![self isVisible] && sender != nil) {
456
        [self makeKeyAndOrderFront: sender];
457
        return;
458
459
    }

460
    BOOL b_activeVideo = [[VLCMain sharedInstance] activeVideoPlayback];
461
    BOOL b_restored = NO;
462

463
464
    // TODO: implement toggle playlist in this situation (triggerd via menu item).
    // but for now we block this case, to avoid displaying only the half
465
    if (b_nativeFullscreenMode && b_fullscreen && b_activeVideo && sender != nil)
466
467
        return;

468
    if (b_dropzone_active && ([[NSApp currentEvent] modifierFlags] & NSAlternateKeyMask) != 0) {
469
470
471
472
        [self hideDropZone];
        return;
    }

473
474
475
476
    if (!(b_nativeFullscreenMode && b_fullscreen) && !b_splitview_removed && ((([[NSApp currentEvent] modifierFlags] & NSAlternateKeyMask) != 0 && b_activeVideo)
                                                                              || (b_nonembedded && sender != nil)
                                                                              || (!b_activeVideo && sender != nil)
                                                                              || b_minimized_view))
477
        [self hideSplitView];
478
479
480
    else {
        if (b_splitview_removed) {
            if (!b_nonembedded || (sender != nil && b_nonembedded))
481
                [self showSplitView];
482
483
484
485
486
487
488
489

            if (sender == nil)
                b_minimized_view = YES;
            else
                b_minimized_view = NO;

            if (b_activeVideo)
                b_restored = YES;
490
491
        }

492
493
        if (!b_nonembedded) {
            if (([o_video_view isHidden] && b_activeVideo) || b_restored || (b_activeVideo && sender == nil))
494
                [self makeSplitViewHidden];
495
            else
496
                [self makeSplitViewVisible];
497
        } else {
498
            [o_split_view setHidden: NO];
499
            [o_playlist_table setHidden: NO];
500
            [o_video_view setHidden: !b_activeVideo];
501
            if (b_activeVideo && [[o_video_view subviews] count] > 0)
502
                [[o_video_view window] makeFirstResponder: [[o_video_view subviews] objectAtIndex:0]];
503
        }
504
505
506
    }
}

507
508
509
510
511
- (IBAction)dropzoneButtonAction:(id)sender
{
    [[[VLCMain sharedInstance] open] openFileGeneric];
}

512
513
514
#pragma mark -
#pragma mark overwritten default functionality

515
516
517
518
519
- (void)windowResizedOrMoved:(NSNotification *)notification
{
    [self saveFrameUsingName: [self frameAutosaveName]];
}

520
521
522
523
524
- (void)applicationWillTerminate:(NSNotification *)notification
{
    [self saveFrameUsingName: [self frameAutosaveName]];
}

525

526
527
- (void)someWindowWillClose:(NSNotification *)notification
{
528
529
    id obj = [notification object];
    if (obj == o_detached_video_window || obj == o_extra_video_window || (obj == self && !b_nonembedded)) {
530
531
532
        if ([[VLCMain sharedInstance] activeVideoPlayback])
            [[VLCCoreInteraction sharedInstance] stop];
    }
533
534
535
536
}

- (void)someWindowWillMiniaturize:(NSNotification *)notification
{
537
    if (config_GetInt(VLCIntf, "macosx-pause-minimized")) {
538
539
        id obj = [notification object];
        if (obj == o_detached_video_window || obj == o_extra_video_window || (obj == self && !b_nonembedded)) {
540
            if ([[VLCMain sharedInstance] activeVideoPlayback])
541
542
                [[VLCCoreInteraction sharedInstance] pause];
        }
543
544
545
    }
}

546
547
548
549
550
551
- (NSSize)windowWillResize:(NSWindow *)window toSize:(NSSize)proposedFrameSize
{
    id videoWindow = [o_video_view window];
    if (![[VLCMain sharedInstance] activeVideoPlayback] || nativeVideoSize.width == 0. || nativeVideoSize.height == 0. || window != videoWindow)
        return proposedFrameSize;

552
    // needed when entering lion fullscreen mode
553
    if (b_fullscreen)
554
        return proposedFrameSize;
555

556
    if ([[VLCCoreInteraction sharedInstance] aspectRatioIsLocked]) {
557
558
559
560
561
        NSRect videoWindowFrame = [videoWindow frame];
        NSRect viewRect = [o_video_view convertRect:[o_video_view bounds] toView: nil];
        NSRect contentRect = [videoWindow contentRectForFrameRect:videoWindowFrame];
        float marginy = viewRect.origin.y + videoWindowFrame.size.height - contentRect.size.height;
        float marginx = contentRect.size.width - viewRect.size.width;
562
        if (b_dark_interface)// && b_video_deco)
563
            marginy += [o_titlebar_view frame].size.height;
564
565
566
567
568
569
570

        proposedFrameSize.height = (proposedFrameSize.width - marginx) * nativeVideoSize.height / nativeVideoSize.width + marginy;
    }

    return proposedFrameSize;
}

571
572
#pragma mark -
#pragma mark Update interface and respond to foreign events
573
574
- (void)showDropZone
{
575
    b_dropzone_active = YES;
576
    [o_right_split_view addSubview: o_dropzone_view positioned:NSWindowAbove relativeTo:o_playlist_table];
577
    [o_dropzone_view setFrame: [o_playlist_table frame]];
578
    [[o_playlist_table animator] setHidden:YES];
579
580
581
582
}

- (void)hideDropZone
{
583
    b_dropzone_active = NO;
584
    [o_dropzone_view removeFromSuperview];
585
    [[o_playlist_table animator] setHidden: NO];
586
587
}

588
589
590
591
592
593
594
595
- (void)hideSplitView
{
    NSRect winrect = [self frame];
    i_lastSplitViewHeight = [o_split_view frame].size.height;
    winrect.size.height = winrect.size.height - i_lastSplitViewHeight;
    winrect.origin.y = winrect.origin.y + i_lastSplitViewHeight;
    [self setFrame: winrect display: YES animate: YES];
    [self performSelector:@selector(hideDropZone) withObject:nil afterDelay:0.1];
596
    if (b_dark_interface) {
597
598
        [self setContentMinSize: NSMakeSize(604., [[o_controls_bar bottomBarView] frame].size.height + [o_titlebar_view frame].size.height)];
        [self setContentMaxSize: NSMakeSize(FLT_MAX, [[o_controls_bar bottomBarView] frame].size.height + [o_titlebar_view frame].size.height)];
599
    } else {
600
601
        [self setContentMinSize: NSMakeSize(604., [[o_controls_bar bottomBarView] frame].size.height)];
        [self setContentMaxSize: NSMakeSize(FLT_MAX, [[o_controls_bar bottomBarView] frame].size.height)];
602
    }
603

604
605
606
607
608
    b_splitview_removed = YES;
}

- (void)showSplitView
{
609
    [self updateWindow];
610
    if (b_dark_interface)
611
        [self setContentMinSize:NSMakeSize(604., 288. + [o_titlebar_view frame].size.height)];
612
    else
613
614
        [self setContentMinSize:NSMakeSize(604., 288.)];
    [self setContentMaxSize: NSMakeSize(FLT_MAX, FLT_MAX)];
615
616
617
618
619
620
621
622
623
624
625
626

    NSRect winrect;
    winrect = [self frame];
    winrect.size.height = winrect.size.height + i_lastSplitViewHeight;
    winrect.origin.y = winrect.origin.y - i_lastSplitViewHeight;
    [self setFrame: winrect display: YES animate: YES];

    [self performSelector:@selector(resizePlaylistAfterCollapse) withObject: nil afterDelay:0.75];

    b_splitview_removed = NO;
}

627
628
- (void)updateTimeSlider
{
629
630
631
    [o_controls_bar updateTimeSlider];
    [[self controlsBar] updatePosAndTimeInFSPanel:o_fspanel];
    [[o_detached_video_window controlsBar] updateTimeSlider];
632
633
}

634
- (void)updateName
635
636
{
    input_thread_t * p_input;
637
638
    p_input = pl_CurrentInput(VLCIntf);
    if (p_input) {
639
        NSString *aString;
640
641
642
        char *format = var_InheritString(VLCIntf, "input-title-format");
        char *formated = str_format_meta(pl_Get(VLCIntf), format);
        free(format);
643
        aString = [NSString stringWithUTF8String:formated];
644
        free(formated);
645

646
        char *uri = input_item_GetURI(input_GetItem(p_input));
647

648
        NSURL * o_url = [NSURL URLWithString: [NSString stringWithUTF8String: uri]];
649
        if ([o_url isFileURL]) {
650
            [self setRepresentedURL: o_url];
651
652
            [o_detached_video_window setRepresentedURL: o_url];
        } else {
653
            [self setRepresentedURL: nil];
654
655
            [o_detached_video_window setRepresentedURL: nil];
        }
656
        free(uri);
657

658
        if ([aString isEqualToString:@""]) {
659
660
661
662
            if ([o_url isFileURL])
                aString = [[NSFileManager defaultManager] displayNameAtPath: [o_url path]];
            else
                aString = [o_url absoluteString];
663
        }
664
665

        [self setTitle: aString];
666
667
668
        if (b_nonembedded && [[VLCMain sharedInstance] activeVideoPlayback])
            [o_detached_video_window setTitle: aString];

669
        [o_fspanel setStreamTitle: aString];
670
671
        vlc_object_release(p_input);
    } else {
672
        [self setTitle: _NS("VLC media player")];
673
        [self setRepresentedURL: nil];
674
    }
675
676
}

677
678
- (void)updateWindow
{
679
680
681
    [o_controls_bar updateControls];
    [[o_detached_video_window controlsBar] updateControls];

682
683
    bool b_seekable = false;

684
685
    playlist_t * p_playlist = pl_Get(VLCIntf);
    input_thread_t * p_input = playlist_CurrentInput(p_playlist);
686
    if (p_input) {
687
        /* seekable streams */
688
        b_seekable = var_GetBool(p_input, "can-seek");
689

690
        vlc_object_release(p_input);
691
692
    }

693
    [self updateTimeSlider];
694
    [o_fspanel setSeekable: b_seekable];
695
696

    PL_LOCK;
697
    if ([[[VLCMain sharedInstance] playlist] currentPlaylistRoot] != p_playlist->p_local_category || p_playlist->p_local_category->i_children > 0)
698
699
700
701
        [self hideDropZone];
    else
        [self showDropZone];
    PL_UNLOCK;
702
    [o_sidebar_view setNeedsDisplay:YES];
703
704
705
706
}

- (void)setPause
{
707
708
    [o_controls_bar setPause];
    [[o_detached_video_window controlsBar] setPause];
709
    [o_fspanel setPause];
710
711
712
713
}

- (void)setPlay
{
714
715
    [o_controls_bar setPlay];
    [[o_detached_video_window controlsBar] setPlay];
716
    [o_fspanel setPlay];
717
718
}

719
- (void)updateVolumeSlider
720
{
721
722
    [[self controlsBar] updateVolumeSlider];
    [o_fspanel setVolumeLevel: [[VLCCoreInteraction sharedInstance] volume]];
723
724
}

725
726
727
#pragma mark -
#pragma mark Video Output handling
- (id)videoView
728
729
730
731
{
    return o_video_view;
}

732
- (void)setupVideoView
733
{
734
735
736
    BOOL b_video_deco = var_InheritBool(VLCIntf, "video-deco");
    BOOL b_video_wallpaper = var_InheritBool(VLCIntf, "video-wallpaper");

737
    // TODO: make lion fullscreen compatible with video-wallpaper and !embedded-video
738
739
740
741
    if ((b_video_wallpaper || !b_video_deco) && !b_nativeFullscreenMode) {
        // b_video_wallpaper is priorized over !b_video_deco

        msg_Dbg(VLCIntf, "Creating background / blank window");
742
743
        NSScreen *screen = [NSScreen screenWithDisplayID:(CGDirectDisplayID)var_InheritInteger(VLCIntf, "macosx-vdev")];
        if (!screen)
744
            screen = [self screen];
745
746
747
748
749

        NSRect window_rect;
        if (b_video_wallpaper)
            window_rect = [screen frame];
        else
750
            window_rect = [self frame];
751

752
        if (o_extra_video_window)
753
754
            [o_extra_video_window release];

755
756
757
758
759
        NSUInteger mask = NSBorderlessWindowMask;
        if (!OSX_SNOW_LEOPARD && !b_video_deco)
            mask |= NSResizableWindowMask;

        BOOL b_no_video_deco_only = !b_video_wallpaper;
760
        o_extra_video_window = [[VLCVideoWindowCommon alloc] initWithContentRect:window_rect styleMask:mask backing:NSBackingStoreBuffered defer:YES];
761
762
763
764
765
        [o_extra_video_window setDelegate:self];

        if (b_video_wallpaper)
            [o_extra_video_window setLevel:CGWindowLevelForKey(kCGDesktopWindowLevelKey) + 1];

766
        [o_extra_video_window setBackgroundColor: [NSColor blackColor]];
767
768
769
770
        [o_extra_video_window setCanBecomeKeyWindow: !b_video_wallpaper];
        [o_extra_video_window setCanBecomeMainWindow: !b_video_wallpaper];
        [o_extra_video_window setAcceptsMouseMovedEvents:!b_video_wallpaper];
        [o_extra_video_window setMovableByWindowBackground: !b_video_wallpaper];
771
        [o_extra_video_window useOptimizedDrawing: YES];
772

773
774
        [o_video_view retain];
        if ([o_video_view superview] != NULL)
775
            [o_video_view removeFromSuperviewWithoutNeedingDisplay];
776
777
        window_rect.origin.x = window_rect.origin.y = 0;
        [o_video_view setFrame: window_rect];
778
779
780
        [[o_extra_video_window contentView] addSubview: o_video_view positioned:NSWindowAbove relativeTo:nil];
        [o_video_view release];

781
782
783
        if (b_video_wallpaper)
            [o_extra_video_window orderBack:nil];
        else {
784
            [o_extra_video_window center];
785
            [o_extra_video_window setFrameAutosaveName:@"extra-videowindow"];
786
            [o_extra_video_window setContentMinSize: NSMakeSize(f_min_video_height, f_min_video_height)];
787
        }
788
789

        b_nonembedded = YES;
790
    } else {
791
        if (var_InheritBool(VLCIntf, "embedded-video") || b_nativeFullscreenMode) {
792
            if ([o_video_view window] != self) {
793
794
795
796
797
                [o_video_view removeFromSuperviewWithoutNeedingDisplay];
                [o_video_view setFrame: [o_split_view frame]];
                [[self contentView] addSubview:o_video_view positioned:NSWindowAbove relativeTo:nil];
            }
            b_nonembedded = NO;
798
        } else {
799
800
801
            if ([o_video_view superview] != NULL)
                [o_video_view removeFromSuperviewWithoutNeedingDisplay];

802
803
            NSRect videoFrame;
            videoFrame.size = [[o_detached_video_window contentView] frame].size;
804
            videoFrame.size.height -= [[[o_detached_video_window controlsBar] bottomBarView] frame].size.height;
805
            if (b_dark_interface)
806
                videoFrame.size.height -= [o_titlebar_view frame].size.height;
807
808

            videoFrame.origin.x = .0;
809
            videoFrame.origin.y = [[[o_detached_video_window controlsBar] bottomBarView] frame].size.height;
810
811

            [o_video_view setFrame: videoFrame];
812
813
814
815
            [[o_detached_video_window contentView] addSubview: o_video_view positioned:NSWindowAbove relativeTo:nil];
            [o_detached_video_window setLevel:NSNormalWindowLevel];
            [o_detached_video_window useOptimizedDrawing: YES];
            b_nonembedded = YES;
816
        }
817
    }
818

819
    if (!b_video_wallpaper) {
820
821
822
        [[o_video_view window] makeKeyAndOrderFront: self];

        vout_thread_t *p_vout = getVout();
823
824
        if (p_vout) {
            if (var_GetBool(p_vout, "video-on-top"))
825
826
827
                [[o_video_view window] setLevel: NSStatusWindowLevel];
            else
                [[o_video_view window] setLevel: NSNormalWindowLevel];
828
            vlc_object_release(p_vout);
829
        }
830
    }
831

832
    [[o_video_view window] setAlphaValue: config_GetFloat(VLCIntf, "macosx-opaqueness")];
833
834
}

835
- (void)setVideoplayEnabled
836
{
837
838
    BOOL b_videoPlayback = [[VLCMain sharedInstance] activeVideoPlayback];

839
    if (b_videoPlayback) {
840
841
        frameBeforePlayback = [self frame];

842
843
        //