MainWindow.m 70.1 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
#import "ControlsBar.h"
46
#import "VideoView.h"
47 48


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

@end

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

59
static VLCMainWindow *_o_sharedInstance = nil;
60

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

#pragma mark -
#pragma mark Initialization

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

    return _o_sharedInstance;
}

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

    [[VLCMain sharedInstance] updateTogglePlaylistState];

    return self;
}

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

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

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

103 104
    NSString * characters = [o_event charactersIgnoringModifiers];
    if ([characters length] > 0) {
105
        return [[characters lowercaseString] isEqualToString: [[VLCStringUtility sharedInstance] VLCKeyToString: o_key]] &&
106 107 108 109 110 111
                (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;
112 113
}

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

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

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

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

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

146 147 148 149 150
    if (o_detached_video_window) {
        [o_detached_video_window release];
        o_detached_video_window = nil;
    }

151 152 153 154 155
    [super dealloc];
}

- (void)awakeFromNib
{
156
    BOOL b_splitviewShouldBeHidden = NO;
157

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

170
    [o_dropzone_btn setTitle: _NS("Open media...")];
171
    [[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];
172
    [o_dropzone_lbl setStringValue: _NS("Drop media here")];
173

174 175
    [o_podcast_add_btn setTitle: _NS("Subscribe")];
    [o_podcast_remove_btn setTitle: _NS("Unsubscribe")];
176 177 178 179
    [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")];
180 181 182 183
    [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")];
184

185
    /* interface builder action */
186
    float f_threshold_height = f_min_video_height + [[o_controls_bar bottomBarView] frame].size.height;
187
    if (b_dark_interface)
188
        f_threshold_height += [o_titlebar_view frame].size.height;
189
    if ([[self contentView] frame].size.height < f_threshold_height)
190
        b_splitviewShouldBeHidden = YES;
191

192 193
    [self setDelegate: self];
    [self setExcludedFromWindowsMenu: YES];
194
    [self setAcceptsMouseMovedEvents: YES];
195
    // Set that here as IB seems to be buggy
196
    if (b_dark_interface) {
197
        [self setContentMinSize:NSMakeSize(604., 288. + [o_titlebar_view frame].size.height)];
198
    } else {
199
        [self setContentMinSize:NSMakeSize(604., 288.)];
200
    }
201

202
    [self setTitle: _NS("VLC media player")];
203

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

216
    if (!OSX_SNOW_LEOPARD) {
217 218 219 220 221 222 223
        /* 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];
    }
224

225 226 227 228
    /* create the sidebar */
    o_sidebaritems = [[NSMutableArray alloc] init];
    SideBarItem *libraryItem = [SideBarItem itemWithTitle:_NS("LIBRARY") identifier:@"library"];
    SideBarItem *playlistItem = [SideBarItem itemWithTitle:_NS("Playlist") identifier:@"playlist"];
229
    [playlistItem setIcon: [NSImage imageNamed:@"sidebar-playlist"]];
230 231
    SideBarItem *medialibraryItem = [SideBarItem itemWithTitle:_NS("Media Library") identifier:@"medialibrary"];
    [medialibraryItem setIcon: [NSImage imageNamed:@"sidebar-playlist"]];
232 233 234 235 236 237 238 239
    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;
240
    char **ppsz_names = vlc_sd_GetNames(pl_Get(VLCIntf), &ppsz_longnames, &p_categories);
241
    if (!ppsz_names)
242
        msg_Err(VLCIntf, "no sd item found"); //TODO
243 244 245 246 247 248
    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];
249
    NSString *o_identifier;
250
    for (; *ppsz_name; ppsz_name++, ppsz_longname++, p_category++) {
251
        o_identifier = [NSString stringWithCString: *ppsz_name encoding: NSUTF8StringEncoding];
252 253
        switch (*p_category) {
            case SD_CAT_INTERNET:
254
                    [internetItems addObject: [SideBarItem itemWithTitle: _NS(*ppsz_longname) identifier: o_identifier]];
255
                    if (!strncmp(*ppsz_name, "podcast", 7))
256
                        [[internetItems lastObject] setIcon: [NSImage imageNamed:@"sidebar-podcast"]];
257 258
                    else
                        [[internetItems lastObject] setIcon: [NSImage imageNamed:@"NSApplicationIcon"]];
259
                    [[internetItems lastObject] setSdtype: SD_CAT_INTERNET];
260
                    [[internetItems lastObject] setUntranslatedTitle: [NSString stringWithUTF8String: *ppsz_longname]];
261 262
                break;
            case SD_CAT_DEVICES:
263
                    [devicesItems addObject: [SideBarItem itemWithTitle: _NS(*ppsz_longname) identifier: o_identifier]];
264
                    [[devicesItems lastObject] setIcon: [NSImage imageNamed:@"NSApplicationIcon"]];
265
                    [[devicesItems lastObject] setSdtype: SD_CAT_DEVICES];
266
                    [[devicesItems lastObject] setUntranslatedTitle: [NSString stringWithUTF8String: *ppsz_longname]];
267 268
                break;
            case SD_CAT_LAN:
269
                    [lanItems addObject: [SideBarItem itemWithTitle: _NS(*ppsz_longname) identifier: o_identifier]];
270
                    [[lanItems lastObject] setIcon: [NSImage imageNamed:@"sidebar-local"]];
271
                    [[lanItems lastObject] setSdtype: SD_CAT_LAN];
272
                    [[lanItems lastObject] setUntranslatedTitle: [NSString stringWithUTF8String: *ppsz_longname]];
273 274
                break;
            case SD_CAT_MYCOMPUTER:
275
                    [mycompItems addObject: [SideBarItem itemWithTitle: _NS(*ppsz_longname) identifier: o_identifier]];
276
                    if (!strncmp(*ppsz_name, "video_dir", 9))
277
                        [[mycompItems lastObject] setIcon: [NSImage imageNamed:@"sidebar-movie"]];
278
                    else if (!strncmp(*ppsz_name, "audio_dir", 9))
279
                        [[mycompItems lastObject] setIcon: [NSImage imageNamed:@"sidebar-music"]];
280
                    else if (!strncmp(*ppsz_name, "picture_dir", 11))
281
                        [[mycompItems lastObject] setIcon: [NSImage imageNamed:@"sidebar-pictures"]];
282 283
                    else
                        [[mycompItems lastObject] setIcon: [NSImage imageNamed:@"NSApplicationIcon"]];
284
                    [[mycompItems lastObject] setUntranslatedTitle: [NSString stringWithUTF8String: *ppsz_longname]];
285
                    [[mycompItems lastObject] setSdtype: SD_CAT_MYCOMPUTER];
286 287
                break;
            default:
288
                msg_Warn(VLCIntf, "unknown SD type found, skipping (%s)", *ppsz_name);
289 290 291
                break;
        }

292 293
        free(*ppsz_name);
        free(*ppsz_longname);
294 295 296 297 298 299 300 301 302
    }
    [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];
303 304 305
    free(ppsz_names);
    free(ppsz_longnames);
    free(p_categories);
306

307
    [libraryItem setChildren: [NSArray arrayWithObjects: playlistItem, medialibraryItem, nil]];
308 309 310 311 312 313 314 315 316 317 318
    [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];
319
    [o_sidebar_view selectRowIndexes:[NSIndexSet indexSetWithIndex:1] byExtendingSelection:NO];
320 321
    [o_sidebar_view setDropItem:playlistItem dropChildIndex:NSOutlineViewDropOnItemIndex];
    [o_sidebar_view registerForDraggedTypes:[NSArray arrayWithObjects: NSFilenamesPboardType, @"VLCPlaylistItemPboardType", nil]];
322

323 324 325 326 327
    [o_sidebar_view setAutosaveName:@"mainwindow-sidebar"];
    [(PXSourceList *)o_sidebar_view setDataSource:self];
    [o_sidebar_view setDelegate:self];
    [o_sidebar_view setAutosaveExpandedItems:YES];

328 329 330 331
    [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];
332
    if (![defaults objectForKey:@"VLCFirstRun"]) {
333 334 335 336 337 338 339
        [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];
    }

340
    if (b_dark_interface) {
341 342 343
        [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(windowResizedOrMoved:) name: NSWindowDidResizeNotification object: nil];
        [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(windowResizedOrMoved:) name: NSWindowDidMoveNotification object: nil];

344 345
        [self setBackgroundColor: [NSColor clearColor]];
        [self setOpaque: NO];
346 347
        [self display];
        [self setHasShadow:NO];
348
        [self setHasShadow:YES];
349

350
        NSRect winrect = [self frame];
351 352
        CGFloat f_titleBarHeight = [o_titlebar_view frame].size.height;

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

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

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

367 368 369
        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];
370
        
371
    } else {
372
        [o_video_view setFrame: [o_split_view frame]];
373 374 375
        [o_playlist_table setBorderType: NSNoBorder];
        [o_sidebar_scrollview setBorderType: NSNoBorder];
    }
376

377
    [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(someWindowWillClose:) name: NSWindowWillCloseNotification object: nil];
378
    [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(someWindowWillMiniaturize:) name: NSWindowWillMiniaturizeNotification object:nil];
379
    [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(applicationWillTerminate:) name: NSApplicationWillTerminateNotification object: nil];
380

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

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

396
#pragma mark -
397

398
- (VLCMainWindowControlsBar *)controlsBar;
399
{
400
    return (VLCMainWindowControlsBar *)o_controls_bar;
401 402
}

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

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

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

    NSRect old_frame = [self frame];
    float newHeight = [self minSize].height;
427
    if (old_frame.size.height < newHeight) {
428 429 430 431 432 433 434 435 436 437 438 439 440 441 442
        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
{
443 444
    if (b_dark_interface)
        [self setContentMinSize: NSMakeSize(604., f_min_video_height + [o_titlebar_view frame].size.height)];
445
    else
446
        [self setContentMinSize: NSMakeSize(604., f_min_video_height)];
447 448 449

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

451
    if ([[o_video_view subviews] count] > 0)
452
        [self makeFirstResponder: [[o_video_view subviews] objectAtIndex:0]];
453 454
}

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

463
    BOOL b_activeVideo = [[VLCMain sharedInstance] activeVideoPlayback];
464
    BOOL b_restored = NO;
465

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

471
    if (b_dropzone_active && ([[NSApp currentEvent] modifierFlags] & NSAlternateKeyMask) != 0) {
472 473 474 475
        [self hideDropZone];
        return;
    }

476 477 478 479
    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))
480
        [self hideSplitView];
481 482 483
    else {
        if (b_splitview_removed) {
            if (!b_nonembedded || (sender != nil && b_nonembedded))
484
                [self showSplitView];
485 486 487 488 489 490 491 492

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

            if (b_activeVideo)
                b_restored = YES;
493 494
        }

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

510 511 512 513 514
- (IBAction)dropzoneButtonAction:(id)sender
{
    [[[VLCMain sharedInstance] open] openFileGeneric];
}

515 516 517
#pragma mark -
#pragma mark overwritten default functionality

518 519 520 521 522
- (void)windowResizedOrMoved:(NSNotification *)notification
{
    [self saveFrameUsingName: [self frameAutosaveName]];
}

523 524 525 526 527
- (void)applicationWillTerminate:(NSNotification *)notification
{
    [self saveFrameUsingName: [self frameAutosaveName]];
}

528

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

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

549 550 551 552 553 554
- (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;

555
    // needed when entering lion fullscreen mode
556
    if (b_fullscreen)
557
        return proposedFrameSize;
558

559
    if ([[VLCCoreInteraction sharedInstance] aspectRatioIsLocked]) {
560 561 562 563 564
        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;
565
        if (b_dark_interface)// && b_video_deco)
566
            marginy += [o_titlebar_view frame].size.height;
567 568 569 570 571 572 573

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

    return proposedFrameSize;
}

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

- (void)hideDropZone
{
586
    b_dropzone_active = NO;
587
    [o_dropzone_view removeFromSuperview];
588
    [[o_playlist_table animator] setHidden: NO];
589 590
}

591 592 593 594 595 596 597 598
- (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];
599
    if (b_dark_interface) {
600 601
        [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)];
602
    } else {
603 604
        [self setContentMinSize: NSMakeSize(604., [[o_controls_bar bottomBarView] frame].size.height)];
        [self setContentMaxSize: NSMakeSize(FLT_MAX, [[o_controls_bar bottomBarView] frame].size.height)];
605
    }
606

607 608 609 610 611
    b_splitview_removed = YES;
}

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

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

630 631
- (void)updateTimeSlider
{
632 633
    [o_controls_bar updateTimeSlider];
    [[self controlsBar] updatePosAndTimeInFSPanel:o_fspanel];
634 635
    if (o_detached_video_window)
        [[o_detached_video_window controlsBar] updateTimeSlider];
636 637
}

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

650
        char *uri = input_item_GetURI(input_GetItem(p_input));
651

652
        NSURL * o_url = [NSURL URLWithString: [NSString stringWithUTF8String: uri]];
653
        if ([o_url isFileURL]) {
654
            [self setRepresentedURL: o_url];
655 656
            if (o_detached_video_window)
                [o_detached_video_window setRepresentedURL: o_url];
657
        } else {
658
            [self setRepresentedURL: nil];
659 660
            if (o_detached_video_window)
                [o_detached_video_window setRepresentedURL: nil];
661
        }
662
        free(uri);
663

664
        if ([aString isEqualToString:@""]) {
665 666 667 668
            if ([o_url isFileURL])
                aString = [[NSFileManager defaultManager] displayNameAtPath: [o_url path]];
            else
                aString = [o_url absoluteString];
669
        }
670 671

        [self setTitle: aString];
672
        if (b_nonembedded && o_detached_video_window && [[VLCMain sharedInstance] activeVideoPlayback])
673 674
            [o_detached_video_window setTitle: aString];

675
        [o_fspanel setStreamTitle: aString];
676 677
        vlc_object_release(p_input);
    } else {
678
        [self setTitle: _NS("VLC media player")];
679
        [self setRepresentedURL: nil];
680
    }
681 682
}

683 684
- (void)updateWindow
{
685
    [o_controls_bar updateControls];
686 687
    if (o_detached_video_window)
        [[o_detached_video_window controlsBar] updateControls];
688

689 690
    bool b_seekable = false;

691 692
    playlist_t * p_playlist = pl_Get(VLCIntf);
    input_thread_t * p_input = playlist_CurrentInput(p_playlist);
693
    if (p_input) {
694
        /* seekable streams */
695
        b_seekable = var_GetBool(p_input, "can-seek");
696

697
        vlc_object_release(p_input);
698 699
    }

700
    [self updateTimeSlider];
701
    [o_fspanel setSeekable: b_seekable];
702 703

    PL_LOCK;
704
    if ([[[VLCMain sharedInstance] playlist] currentPlaylistRoot] != p_playlist->p_local_category || p_playlist->p_local_category->i_children > 0)
705 706 707 708
        [self hideDropZone];
    else
        [self showDropZone];
    PL_UNLOCK;
709
    [o_sidebar_view setNeedsDisplay:YES];
710 711 712 713
}

- (void)setPause
{
714
    [o_controls_bar setPause];
715 716
    if (o_detached_video_window)
        [[o_detached_video_window controlsBar] setPause];
717
    [o_fspanel setPause];
718 719 720 721
}

- (void)setPlay
{
722
    [o_controls_bar setPlay];
723 724
    if (o_detached_video_window)
        [[o_detached_video_window controlsBar] setPlay];
725
    [o_fspanel setPlay];
726 727
}

728
- (void)updateVolumeSlider
729
{
730 731
    [[self controlsBar] updateVolumeSlider];
    [o_fspanel setVolumeLevel: [[VLCCoreInteraction sharedInstance] volume]];
732 733
}

734 735
#pragma mark -
#pragma mark Video Output handling