You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2557 lines
90 KiB

/*****************************************************************************
* MainWindow.m: MacOS X interface module
*****************************************************************************
* Copyright (C) 2002-2012 VLC authors and VideoLAN
* $Id$
*
* Authors: Felix Paul Kühne <fkuehne -at- videolan -dot- org>
* Jon Lech Johansen <jon-vl@nanocrew.net>
* Christophe Massiot <massiot@via.ecp.fr>
* Derk-Jan Hartman <hartman at videolan.org>
*
* 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.
*****************************************************************************/
#import "CompatibilityFixes.h"
#import "MainWindow.h"
#import "intf.h"
#import "CoreInteraction.h"
#import "AudioEffects.h"
#import "MainMenu.h"
#import "open.h"
#import "controls.h" // TODO: remove me
#import "playlist.h"
#import "SideBarItem.h"
#import <vlc_playlist.h>
#import <vlc_aout_intf.h>
#import <vlc_url.h>
#import <vlc_strings.h>
#import <vlc_services_discovery.h>
#import <vlc_aout_intf.h>
@implementation VLCMainWindow
static VLCMainWindow *_o_sharedInstance = nil;
+ (VLCMainWindow *)sharedInstance
{
return _o_sharedInstance ? _o_sharedInstance : [[self alloc] init];
}
#pragma mark -
#pragma mark Initialization
- (id)init
{
if( _o_sharedInstance)
{
[self dealloc];
return _o_sharedInstance;
}
else
{
o_fspanel = [[VLCFSPanel alloc] init];
_o_sharedInstance = [super init];
}
return _o_sharedInstance;
}
- (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)styleMask
backing:(NSBackingStoreType)backingType defer:(BOOL)flag
{
b_dark_interface = config_GetInt( VLCIntf, "macosx-interfacestyle" );
if (b_dark_interface)
{
#ifdef MAC_OS_X_VERSION_10_7
if (OSX_LION)
styleMask = NSBorderlessWindowMask | NSResizableWindowMask;
else
styleMask = NSBorderlessWindowMask;
#else
styleMask = NSBorderlessWindowMask;
#endif
}
self = [super initWithContentRect:contentRect styleMask:styleMask
backing:backingType defer:flag];
[[VLCMain sharedInstance] updateTogglePlaylistState];
/* we want to be moveable regardless of our style */
[self setMovableByWindowBackground: YES];
/* we don't want this window to be restored on relaunch */
if (OSX_LION)
[self setRestorable:NO];
return self;
}
- (BOOL)performKeyEquivalent:(NSEvent *)o_event
{
/* We indeed want to prioritize Cocoa key equivalent against libvlc,
so we perform the menu equivalent now. */
if([[NSApp mainMenu] performKeyEquivalent:o_event])
return TRUE;
return [[VLCMain sharedInstance] hasDefinedShortcutKey:o_event] || [(VLCControls *)[[VLCMain sharedInstance] controls] keyEvent:o_event];
}
- (void)dealloc
{
if (b_dark_interface)
[o_color_backdrop release];
[[NSNotificationCenter defaultCenter] removeObserver: self];
[o_sidebaritems release];
[super dealloc];
}
- (void)awakeFromNib
{
BOOL b_splitviewShouldBeHidden = NO;
/* setup the styled interface */
b_nativeFullscreenMode = NO;
#ifdef MAC_OS_X_VERSION_10_7
if( OSX_LION )
b_nativeFullscreenMode = config_GetInt( VLCIntf, "macosx-nativefullscreenmode" );
#endif
i_lastShownVolume = -1;
t_hide_mouse_timer = nil;
[o_detached_video_window setDelegate: self];
[self useOptimizedDrawing: YES];
[o_play_btn setToolTip: _NS("Play/Pause")];
[o_detached_play_btn setToolTip: [o_play_btn toolTip]];
[o_bwd_btn setToolTip: _NS("Backward")];
[o_detached_bwd_btn setToolTip: [o_bwd_btn toolTip]];
[o_fwd_btn setToolTip: _NS("Forward")];
[o_detached_fwd_btn setToolTip: [o_fwd_btn toolTip]];
[o_stop_btn setToolTip: _NS("Stop")];
[o_playlist_btn setToolTip: _NS("Show/Hide Playlist")];
[o_repeat_btn setToolTip: _NS("Repeat")];
[o_shuffle_btn setToolTip: _NS("Shuffle")];
[o_effects_btn setToolTip: _NS("Effects")];
[o_fullscreen_btn setToolTip: _NS("Toggle Fullscreen mode")];
[o_detached_fullscreen_btn setToolTip: [o_fullscreen_btn toolTip]];
[[o_search_fld cell] setPlaceholderString: _NS("Search")];
[o_volume_sld setToolTip: _NS("Volume")];
[o_volume_down_btn setToolTip: _NS("Mute")];
[o_volume_up_btn setToolTip: _NS("Full Volume")];
[o_time_sld setToolTip: _NS("Position")];
[o_detached_time_sld setToolTip: [o_time_sld toolTip]];
[o_dropzone_btn setTitle: _NS("Open media...")];
[o_dropzone_lbl setStringValue: _NS("Drop media here")];
if (!b_dark_interface) {
[o_bottombar_view setImagesLeft: [NSImage imageNamed:@"bottom-background"] middle: [NSImage imageNamed:@"bottom-background"] right: [NSImage imageNamed:@"bottom-background"]];
[o_detached_bottombar_view setImagesLeft: [NSImage imageNamed:@"bottom-background"] middle: [NSImage imageNamed:@"bottom-background"] right: [NSImage imageNamed:@"bottom-background"]];
[o_bwd_btn setImage: [NSImage imageNamed:@"back"]];
[o_bwd_btn setAlternateImage: [NSImage imageNamed:@"back-pressed"]];
[o_detached_bwd_btn setImage: [NSImage imageNamed:@"back"]];
[o_detached_bwd_btn setAlternateImage: [NSImage imageNamed:@"back-pressed"]];
o_play_img = [[NSImage imageNamed:@"play"] retain];
o_play_pressed_img = [[NSImage imageNamed:@"play-pressed"] retain];
o_pause_img = [[NSImage imageNamed:@"pause"] retain];
o_pause_pressed_img = [[NSImage imageNamed:@"pause-pressed"] retain];
[o_fwd_btn setImage: [NSImage imageNamed:@"forward"]];
[o_fwd_btn setAlternateImage: [NSImage imageNamed:@"forward-pressed"]];
[o_detached_fwd_btn setImage: [NSImage imageNamed:@"forward"]];
[o_detached_fwd_btn setAlternateImage: [NSImage imageNamed:@"forward-pressed"]];
[o_stop_btn setImage: [NSImage imageNamed:@"stop"]];
[o_stop_btn setAlternateImage: [NSImage imageNamed:@"stop-pressed"]];
[o_playlist_btn setImage: [NSImage imageNamed:@"playlist"]];
[o_playlist_btn setAlternateImage: [NSImage imageNamed:@"playlist-pressed"]];
o_repeat_img = [[NSImage imageNamed:@"repeat"] retain];
o_repeat_pressed_img = [[NSImage imageNamed:@"repeat-pressed"] retain];
o_repeat_all_img = [[NSImage imageNamed:@"repeat-all"] retain];
o_repeat_all_pressed_img = [[NSImage imageNamed:@"repeat-all-pressed"] retain];
o_repeat_one_img = [[NSImage imageNamed:@"repeat-one"] retain];
o_repeat_one_pressed_img = [[NSImage imageNamed:@"repeat-one-pressed"] retain];
o_shuffle_img = [[NSImage imageNamed:@"shuffle"] retain];
o_shuffle_pressed_img = [[NSImage imageNamed:@"shuffle-pressed"] retain];
o_shuffle_on_img = [[NSImage imageNamed:@"shuffle-blue"] retain];
o_shuffle_on_pressed_img = [[NSImage imageNamed:@"shuffle-blue-pressed"] retain];
[o_time_sld_background setImagesLeft: [NSImage imageNamed:@"progression-track-wrapper-left"] middle: [NSImage imageNamed:@"progression-track-wrapper-middle"] right: [NSImage imageNamed:@"progression-track-wrapper-right"]];
[o_detached_time_sld_background setImagesLeft: [NSImage imageNamed:@"progression-track-wrapper-left"] middle: [NSImage imageNamed:@"progression-track-wrapper-middle"] right: [NSImage imageNamed:@"progression-track-wrapper-right"]];
[o_volume_down_btn setImage: [NSImage imageNamed:@"volume-low"]];
[o_volume_track_view setImage: [NSImage imageNamed:@"volume-slider-track"]];
[o_volume_up_btn setImage: [NSImage imageNamed:@"volume-high"]];
if (b_nativeFullscreenMode)
{
[o_effects_btn setImage: [NSImage imageNamed:@"effects-one-button"]];
[o_effects_btn setAlternateImage: [NSImage imageNamed:@"effects-one-button-blue"]];
}
else
{
[o_effects_btn setImage: [NSImage imageNamed:@"effects-double-buttons"]];
[o_effects_btn setAlternateImage: [NSImage imageNamed:@"effects-double-buttons-pressed"]];
}
[o_fullscreen_btn setImage: [NSImage imageNamed:@"fullscreen-double-buttons"]];
[o_fullscreen_btn setAlternateImage: [NSImage imageNamed:@"fullscreen-double-buttons-pressed"]];
[o_detached_fullscreen_btn setImage: [NSImage imageNamed:@"fullscreen-one-button"]];
[o_detached_fullscreen_btn setAlternateImage: [NSImage imageNamed:@"fullscreen-one-button-pressed"]];
[o_time_sld_fancygradient_view setImagesLeft:[NSImage imageNamed:@"progression-fill-left"] middle:[NSImage imageNamed:@"progression-fill-middle"] right:[NSImage imageNamed:@"progression-fill-right"]];
[o_detached_time_sld_fancygradient_view setImagesLeft:[NSImage imageNamed:@"progression-fill-left"] middle:[NSImage imageNamed:@"progression-fill-middle"] right:[NSImage imageNamed:@"progression-fill-right"]];
}
else
{
[o_bottombar_view setImagesLeft: [NSImage imageNamed:@"bottomdark-left"] middle: [NSImage imageNamed:@"bottom-background_dark"] right: [NSImage imageNamed:@"bottomdark-right"]];
[o_detached_bottombar_view setImagesLeft: [NSImage imageNamed:@"bottomdark-left"] middle: [NSImage imageNamed:@"bottom-background_dark"] right: [NSImage imageNamed:@"bottomdark-right"]];
[o_bwd_btn setImage: [NSImage imageNamed:@"back_dark"]];
[o_bwd_btn setAlternateImage: [NSImage imageNamed:@"back-pressed_dark"]];
[o_detached_bwd_btn setImage: [NSImage imageNamed:@"back_dark"]];
[o_detached_bwd_btn setAlternateImage: [NSImage imageNamed:@"back-pressed_dark"]];
o_play_img = [[NSImage imageNamed:@"play_dark"] retain];
o_play_pressed_img = [[NSImage imageNamed:@"play-pressed_dark"] retain];
o_pause_img = [[NSImage imageNamed:@"pause_dark"] retain];
o_pause_pressed_img = [[NSImage imageNamed:@"pause-pressed_dark"] retain];
[o_fwd_btn setImage: [NSImage imageNamed:@"forward_dark"]];
[o_fwd_btn setAlternateImage: [NSImage imageNamed:@"forward-pressed_dark"]];
[o_detached_fwd_btn setImage: [NSImage imageNamed:@"forward_dark"]];
[o_detached_fwd_btn setAlternateImage: [NSImage imageNamed:@"forward-pressed_dark"]];
[o_stop_btn setImage: [NSImage imageNamed:@"stop_dark"]];
[o_stop_btn setAlternateImage: [NSImage imageNamed:@"stop-pressed_dark"]];
[o_playlist_btn setImage: [NSImage imageNamed:@"playlist_dark"]];
[o_playlist_btn setAlternateImage: [NSImage imageNamed:@"playlist-pressed_dark"]];
o_repeat_img = [[NSImage imageNamed:@"repeat_dark"] retain];
o_repeat_pressed_img = [[NSImage imageNamed:@"repeat-pressed_dark"] retain];
o_repeat_all_img = [[NSImage imageNamed:@"repeat-all-blue_dark"] retain];
o_repeat_all_pressed_img = [[NSImage imageNamed:@"repeat-all-blue-pressed_dark"] retain];
o_repeat_one_img = [[NSImage imageNamed:@"repeat-one-blue_dark"] retain];
o_repeat_one_pressed_img = [[NSImage imageNamed:@"repeat-one-blue-pressed_dark"] retain];
o_shuffle_img = [[NSImage imageNamed:@"shuffle_dark"] retain];
o_shuffle_pressed_img = [[NSImage imageNamed:@"shuffle-pressed_dark"] retain];
o_shuffle_on_img = [[NSImage imageNamed:@"shuffle-blue_dark"] retain];
o_shuffle_on_pressed_img = [[NSImage imageNamed:@"shuffle-blue-pressed_dark"] retain];
[o_time_sld_background setImagesLeft: [NSImage imageNamed:@"progression-track-wrapper-left_dark"] middle: [NSImage imageNamed:@"progression-track-wrapper-middle_dark"] right: [NSImage imageNamed:@"progression-track-wrapper-right_dark"]];
[o_detached_time_sld_background setImagesLeft: [NSImage imageNamed:@"progression-track-wrapper-left_dark"] middle: [NSImage imageNamed:@"progression-track-wrapper-middle_dark"] right: [NSImage imageNamed:@"progression-track-wrapper-right_dark"]];
[o_volume_down_btn setImage: [NSImage imageNamed:@"volume-low_dark"]];
[o_volume_track_view setImage: [NSImage imageNamed:@"volume-slider-track_dark"]];
[o_volume_up_btn setImage: [NSImage imageNamed:@"volume-high_dark"]];
if (b_nativeFullscreenMode)
{
[o_effects_btn setImage: [NSImage imageNamed:@"effects-one-button_dark"]];
[o_effects_btn setAlternateImage: [NSImage imageNamed:@"effects-one-button-blue_dark"]];
}
else
{
[o_effects_btn setImage: [NSImage imageNamed:@"effects-double-buttons_dark"]];
[o_effects_btn setAlternateImage: [NSImage imageNamed:@"effects-double-buttons-pressed_dark"]];
}
[o_fullscreen_btn setImage: [NSImage imageNamed:@"fullscreen-double-buttons_dark"]];
[o_fullscreen_btn setAlternateImage: [NSImage imageNamed:@"fullscreen-double-buttons-pressed_dark"]];
[o_detached_fullscreen_btn setImage: [NSImage imageNamed:@"fullscreen-one-button_dark"]];
[o_detached_fullscreen_btn setAlternateImage: [NSImage imageNamed:@"fullscreen-one-button-pressed_dark"]];
[o_time_sld_fancygradient_view setImagesLeft:[NSImage imageNamed:@"progressbar-fill-left_dark"] middle:[NSImage imageNamed:@"progressbar-fill-middle_dark"] right:[NSImage imageNamed:@"progressbar-fill-right_dark"]];
[o_detached_time_sld_fancygradient_view setImagesLeft:[NSImage imageNamed:@"progressbar-fill-left_dark"] middle:[NSImage imageNamed:@"progressbar-fill-middle_dark"] right:[NSImage imageNamed:@"progressbar-fill-right_dark"]];
}
[o_repeat_btn setImage: o_repeat_img];
[o_repeat_btn setAlternateImage: o_repeat_pressed_img];
[o_shuffle_btn setImage: o_shuffle_img];
[o_shuffle_btn setAlternateImage: o_shuffle_pressed_img];
[o_play_btn setImage: o_play_img];
[o_play_btn setAlternateImage: o_play_pressed_img];
[o_detached_play_btn setImage: o_play_img];
[o_detached_play_btn setAlternateImage: o_play_pressed_img];
BOOL b_mute = ![[VLCCoreInteraction sharedInstance] isMuted];
[o_volume_sld setEnabled: b_mute];
[o_volume_up_btn setEnabled: b_mute];
/* interface builder action */
if ([self frame].size.height < 100)
b_splitviewShouldBeHidden = YES;
[self setDelegate: self];
[self setExcludedFromWindowsMenu: YES];
[self setAcceptsMouseMovedEvents: YES];
// Set that here as IB seems to be buggy
if (b_dark_interface)
[self setContentMinSize:NSMakeSize(604., (288. + [o_titlebar_view frame].size.height))];
else
[self setContentMinSize:NSMakeSize(604., 288.)];
[self setTitle: _NS("VLC media player")];
[o_time_fld setAlignment: NSCenterTextAlignment];
[o_time_fld setNeedsDisplay:YES];
b_dropzone_active = YES;
o_temp_view = [[NSView alloc] init];
[o_temp_view setAutoresizingMask:NSViewHeightSizable | NSViewWidthSizable];
[o_dropzone_view setFrame: [o_playlist_table frame]];
[o_left_split_view setFrame: [o_sidebar_view frame]];
if (b_nativeFullscreenMode)
{
NSRect frame;
[self setCollectionBehavior: NSWindowCollectionBehaviorFullScreenPrimary];
float f_width = [o_fullscreen_btn frame].size.width;
#define moveItem( item ) \
frame = [item frame]; \
frame.origin.x = f_width + frame.origin.x; \
[item setFrame: frame]
moveItem( o_effects_btn );
moveItem( o_volume_up_btn );
moveItem( o_volume_sld );
moveItem( o_volume_track_view );
moveItem( o_volume_down_btn );
moveItem( o_time_fld );
#undef moveItem
#define enlargeItem( item ) \
frame = [item frame]; \
frame.size.width = f_width + frame.size.width; \
[item setFrame: frame]
enlargeItem( o_time_sld );
enlargeItem( o_progress_bar );
enlargeItem( o_time_sld_background );
enlargeItem( o_time_sld_fancygradient_view );
#undef enlargeItem
[o_fullscreen_btn removeFromSuperviewWithoutNeedingDisplay];
}
else
{
[o_titlebar_view setFullscreenButtonHidden: YES];
[o_detached_titlebar_view setFullscreenButtonHidden: YES];
}
if (OSX_LION)
{
/* 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];
}
/* create the sidebar */
o_sidebaritems = [[NSMutableArray alloc] init];
SideBarItem *libraryItem = [SideBarItem itemWithTitle:_NS("LIBRARY") identifier:@"library"];
SideBarItem *playlistItem = [SideBarItem itemWithTitle:_NS("Playlist") identifier:@"playlist"];
[playlistItem setIcon: [NSImage imageNamed:@"sidebar-playlist"]];
SideBarItem *medialibraryItem = [SideBarItem itemWithTitle:_NS("Media Library") identifier:@"medialibrary"];
[medialibraryItem setIcon: [NSImage imageNamed:@"sidebar-playlist"]];
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;
char **ppsz_names = vlc_sd_GetNames( pl_Get( VLCIntf ), &ppsz_longnames, &p_categories );
if (!ppsz_names)
msg_Err( VLCIntf, "no sd item found" ); //TODO
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];
NSString *o_identifier;
for (; *ppsz_name; ppsz_name++, ppsz_longname++, p_category++)
{
o_identifier = [NSString stringWithCString: *ppsz_name encoding: NSUTF8StringEncoding];
switch (*p_category) {
case SD_CAT_INTERNET:
{
[internetItems addObject: [SideBarItem itemWithTitle: _NS(*ppsz_longname) identifier: o_identifier]];
if (!strncmp( *ppsz_name, "podcast", 7 ))
[internetItems removeLastObject]; // we don't support podcasts at this point (see #6017)
// [[internetItems lastObject] setIcon: [NSImage imageNamed:@"sidebar-podcast"]];
else
[[internetItems lastObject] setIcon: [NSImage imageNamed:@"NSApplicationIcon"]];
[[internetItems lastObject] setSdtype: SD_CAT_INTERNET];
[[internetItems lastObject] setUntranslatedTitle: [NSString stringWithUTF8String: *ppsz_longname]];
}
break;
case SD_CAT_DEVICES:
{
[devicesItems addObject: [SideBarItem itemWithTitle: _NS(*ppsz_longname) identifier: o_identifier]];
[[devicesItems lastObject] setIcon: [NSImage imageNamed:@"NSApplicationIcon"]];
[[devicesItems lastObject] setSdtype: SD_CAT_DEVICES];
[[devicesItems lastObject] setUntranslatedTitle: [NSString stringWithUTF8String: *ppsz_longname]];
}
break;
case SD_CAT_LAN:
{
[lanItems addObject: [SideBarItem itemWithTitle: _NS(*ppsz_longname) identifier: o_identifier]];
[[lanItems lastObject] setIcon: [NSImage imageNamed:@"sidebar-local"]];
[[lanItems lastObject] setSdtype: SD_CAT_LAN];
[[lanItems lastObject] setUntranslatedTitle: [NSString stringWithUTF8String: *ppsz_longname]];
}
break;
case SD_CAT_MYCOMPUTER:
{
[mycompItems addObject: [SideBarItem itemWithTitle: _NS(*ppsz_longname) identifier: o_identifier]];
if (!strncmp( *ppsz_name, "video_dir", 9 ))
[[mycompItems lastObject] setIcon: [NSImage imageNamed:@"sidebar-movie"]];
else if (!strncmp( *ppsz_name, "audio_dir", 9 ))
[[mycompItems lastObject] setIcon: [NSImage imageNamed:@"sidebar-music"]];
else if (!strncmp( *ppsz_name, "picture_dir", 11 ))
[[mycompItems lastObject] setIcon: [NSImage imageNamed:@"sidebar-pictures"]];
else
[[mycompItems lastObject] setIcon: [NSImage imageNamed:@"NSApplicationIcon"]];
[[mycompItems lastObject] setUntranslatedTitle: [NSString stringWithUTF8String: *ppsz_longname]];
[[mycompItems lastObject] setSdtype: SD_CAT_MYCOMPUTER];
}
break;
default:
msg_Warn( VLCIntf, "unknown SD type found, skipping (%s)", *ppsz_name );
break;
}
free( *ppsz_name );
free( *ppsz_longname );
}
[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];
free( ppsz_names );
free( ppsz_longnames );
free( p_categories );
[libraryItem setChildren: [NSArray arrayWithObjects: playlistItem, medialibraryItem, nil]];
[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];
[o_sidebar_view selectRowIndexes:[NSIndexSet indexSetWithIndex:1] byExtendingSelection:NO];
[o_sidebar_view setDropItem:playlistItem dropChildIndex:NSOutlineViewDropOnItemIndex];
[o_sidebar_view registerForDraggedTypes:[NSArray arrayWithObjects: NSFilenamesPboardType, @"VLCPlaylistItemPboardType", nil]];
[o_sidebar_view setAutosaveName:@"mainwindow-sidebar"];
[(PXSourceList *)o_sidebar_view setDataSource:self];
[o_sidebar_view setDelegate:self];
[o_sidebar_view setAutosaveExpandedItems:YES];
[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];
if (![defaults objectForKey:@"VLCFirstRun"])
{
[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];
}
if( b_dark_interface )
{
[[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(windowResizedOrMoved:) name: NSWindowDidResizeNotification object: nil];
[[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(windowResizedOrMoved:) name: NSWindowDidMoveNotification object: nil];
[self setBackgroundColor: [NSColor clearColor]];
[self setOpaque: NO];
[self display];
[self setHasShadow:NO];
[self setHasShadow:YES];
NSRect winrect = [self frame];
CGFloat f_titleBarHeight = [o_titlebar_view frame].size.height;
[o_titlebar_view setFrame: NSMakeRect( 0, winrect.size.height - f_titleBarHeight,
winrect.size.width, f_titleBarHeight )];
[[self contentView] addSubview: o_titlebar_view positioned: NSWindowAbove relativeTo: o_split_view];
if (winrect.size.height > 100)
{
[self setFrame: winrect display:YES animate:YES];
previousSavedFrame = winrect;
}
winrect = [o_split_view frame];
winrect.size.height = winrect.size.height - f_titleBarHeight;
[o_split_view setFrame: winrect];
[o_video_view setFrame: winrect];
/* detached video window */
winrect = [o_detached_video_window frame];
[o_detached_titlebar_view setFrame: NSMakeRect( 0, winrect.size.height - f_titleBarHeight, winrect.size.width, f_titleBarHeight )];
[[o_detached_video_window contentView] addSubview: o_detached_titlebar_view positioned: NSWindowAbove relativeTo: nil];
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];
}
else
{
NSRect frame;
frame = [o_time_sld_fancygradient_view frame];
frame.size.height = frame.size.height - 1;
frame.origin.y = frame.origin.y + 1;
[o_time_sld_fancygradient_view setFrame: frame];
frame = [o_detached_time_sld_fancygradient_view frame];
frame.size.height = frame.size.height - 1;
frame.origin.y = frame.origin.y + 1;
[o_detached_time_sld_fancygradient_view setFrame: frame];
[o_video_view setFrame: [o_split_view frame]];
[o_playlist_table setBorderType: NSNoBorder];
[o_sidebar_scrollview setBorderType: NSNoBorder];
}
NSRect frame;
frame = [o_time_sld_fancygradient_view frame];
frame.size.width = 0;
[o_time_sld_fancygradient_view setFrame: frame];
frame = [o_detached_time_sld_fancygradient_view frame];
frame.size.width = 0;
[o_detached_time_sld_fancygradient_view setFrame: frame];
if (OSX_LION)
{
[o_resize_view setImage: NULL];
[o_detached_resize_view setImage: NULL];
}
if ([self styleMask] & NSResizableWindowMask)
{
[o_resize_view removeFromSuperviewWithoutNeedingDisplay];
[o_detached_resize_view removeFromSuperviewWithoutNeedingDisplay];
}
[[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(someWindowWillClose:) name: NSWindowWillCloseNotification object: nil];
[[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(someWindowWillMiniaturize:) name: NSWindowWillMiniaturizeNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(applicationWillTerminate:) name: NSApplicationWillTerminateNotification object: nil];
[[VLCMain sharedInstance] playbackModeUpdated];
if (b_splitviewShouldBeHidden)
{
i_lastSplitViewHeight = [o_split_view frame].size.height;
[self hideSplitView];
}
}
#pragma mark -
#pragma mark Button Actions
- (IBAction)play:(id)sender
{
[[VLCCoreInteraction sharedInstance] play];
}
- (void)resetPreviousButton
{
if (([NSDate timeIntervalSinceReferenceDate] - last_bwd_event) >= 0.35) {
// seems like no further event occurred, so let's switch the playback item
[[VLCCoreInteraction sharedInstance] previous];
just_triggered_previous = NO;
}
}
- (void)resetBackwardSkip
{
// the user stopped skipping, so let's allow him to change the item
if (([NSDate timeIntervalSinceReferenceDate] - last_bwd_event) >= 0.35)
just_triggered_previous = NO;
}
- (IBAction)bwd:(id)sender
{
if(!just_triggered_previous)
{
just_triggered_previous = YES;
[self performSelector:@selector(resetPreviousButton)
withObject: NULL
afterDelay:0.40];
}
else
{
if (([NSDate timeIntervalSinceReferenceDate] - last_fwd_event) > 0.16 )
{
// we just skipped 4 "continous" events, otherwise we are too fast
[[VLCCoreInteraction sharedInstance] backwardExtraShort];
last_bwd_event = [NSDate timeIntervalSinceReferenceDate];
[self performSelector:@selector(resetBackwardSkip)
withObject: NULL
afterDelay:0.40];
}
}
}
- (void)resetNextButton
{
if (([NSDate timeIntervalSinceReferenceDate] - last_fwd_event) >= 0.35) {
// seems like no further event occurred, so let's switch the playback item
[[VLCCoreInteraction sharedInstance] next];
just_triggered_next = NO;
}
}
- (void)resetForwardSkip
{
// the user stopped skipping, so let's allow him to change the item
if (([NSDate timeIntervalSinceReferenceDate] - last_fwd_event) >= 0.35)
just_triggered_next = NO;
}
- (IBAction)fwd:(id)sender
{
if(!just_triggered_next)
{
just_triggered_next = YES;
[self performSelector:@selector(resetNextButton)
withObject: NULL
afterDelay:0.40];
}
else
{
if (([NSDate timeIntervalSinceReferenceDate] - last_fwd_event) > 0.16 )
{
// we just skipped 4 "continous" events, otherwise we are too fast
[[VLCCoreInteraction sharedInstance] forwardExtraShort];
last_fwd_event = [NSDate timeIntervalSinceReferenceDate];
[self performSelector:@selector(resetForwardSkip)
withObject: NULL
afterDelay:0.40];
}
}
}
- (IBAction)stop:(id)sender
{
[[VLCCoreInteraction sharedInstance] stop];
}
- (void)resizePlaylistAfterCollapse
{
NSRect plrect;
plrect = [[o_playlist_table animator] frame];
plrect.size.height = i_lastSplitViewHeight - 19.0; // actual pl top bar height, which differs from its frame
[[o_playlist_table animator] setFrame: plrect];
NSRect rightSplitRect;
rightSplitRect = [o_right_split_view frame];
plrect = [[o_dropzone_box animator] frame];
plrect.origin.x = (rightSplitRect.size.width - plrect.size.width) / 2;
plrect.origin.y = (rightSplitRect.size.height - plrect.size.height) / 2;
[[o_dropzone_box animator] setFrame: plrect];
}
- (IBAction)togglePlaylist:(id)sender
{
if (![self isVisible] && sender != nil)
{
[self makeKeyAndOrderFront: sender];
return;
}
BOOL b_activeVideo = [[VLCMain sharedInstance] activeVideoPlayback];
BOOL b_restored = NO;
if (b_dropzone_active && !b_activeVideo && ([[NSApp currentEvent] modifierFlags] & NSAlternateKeyMask) != 0)
{
b_dropzone_active = NO;
[self hideDropZone];
return;
}
if ( !b_splitview_removed && ( (([[NSApp currentEvent] modifierFlags] & NSAlternateKeyMask) != 0 && b_activeVideo)
|| (b_nonembedded && sender != nil)
|| (!b_activeVideo && sender != nil)
|| b_minimized_view ) )
{
[self hideSplitView];
}
else
{
if (b_splitview_removed)
{
if( !b_nonembedded || ( sender != nil && b_nonembedded))
[self showSplitView];
if (sender == nil)
b_minimized_view = YES;
else
b_minimized_view = NO;
if (b_activeVideo)
b_restored = YES;
}
if (!b_nonembedded)
{
if (([o_video_view isHidden] && b_activeVideo) || b_restored ) {
[o_split_view setHidden: YES];
[o_video_view setHidden: NO];
[self makeFirstResponder: o_video_view];
}
else
{
[o_video_view setHidden: YES];
[o_split_view setHidden: NO];
[self makeFirstResponder: nil];
}
}
else
{
[o_split_view setHidden: NO];
[o_playlist_table setHidden: NO];
[o_video_view setHidden: !b_activeVideo];
if (b_activeVideo)
[o_detached_video_window makeFirstResponder: o_video_view];
}
}
}
- (void)setRepeatOne
{
[o_repeat_btn setImage: o_repeat_one_img];
[o_repeat_btn setAlternateImage: o_repeat_one_pressed_img];
}
- (void)setRepeatAll
{
[o_repeat_btn setImage: o_repeat_all_img];
[o_repeat_btn setAlternateImage: o_repeat_all_pressed_img];
}
- (void)setRepeatOff
{
[o_repeat_btn setImage: o_repeat_img];
[o_repeat_btn setAlternateImage: o_repeat_pressed_img];
}
- (IBAction)repeat:(id)sender
{
vlc_value_t looping,repeating;
intf_thread_t * p_intf = VLCIntf;
playlist_t * p_playlist = pl_Get( p_intf );
var_Get( p_playlist, "repeat", &repeating );
var_Get( p_playlist, "loop", &looping );
if( !repeating.b_bool && !looping.b_bool )
{
/* was: no repeating at all, switching to Repeat One */
[[VLCCoreInteraction sharedInstance] repeatOne];
[self setRepeatOne];
}
else if( repeating.b_bool && !looping.b_bool )
{
/* was: Repeat One, switching to Repeat All */
[[VLCCoreInteraction sharedInstance] repeatAll];
[self setRepeatAll];
}
else
{
/* was: Repeat All or bug in VLC, switching to Repeat Off */
[[VLCCoreInteraction sharedInstance] repeatOff];
[self setRepeatOff];
}
}
- (void)setShuffle
{
bool b_value;
playlist_t *p_playlist = pl_Get( VLCIntf );
b_value = var_GetBool( p_playlist, "random" );
if(b_value) {
[o_shuffle_btn setImage: o_shuffle_on_img];
[o_shuffle_btn setAlternateImage: o_shuffle_on_pressed_img];
}
else
{
[o_shuffle_btn setImage: o_shuffle_img];
[o_shuffle_btn setAlternateImage: o_shuffle_pressed_img];
}
}
- (IBAction)shuffle:(id)sender
{
[[VLCCoreInteraction sharedInstance] shuffle];
[self setShuffle];
}
- (IBAction)timeSliderAction:(id)sender
{
float f_updated;
input_thread_t * p_input;
switch( [[NSApp currentEvent] type] )
{
case NSLeftMouseUp:
case NSLeftMouseDown:
case NSLeftMouseDragged:
f_updated = [sender floatValue];
break;
default:
return;
}
p_input = pl_CurrentInput( VLCIntf );
if( p_input != NULL )
{
vlc_value_t time;
vlc_value_t pos;
NSString * o_time;
char psz_time[MSTRTIME_MAX_SIZE];
pos.f_float = f_updated / 10000.;
var_Set( p_input, "position", pos );
[o_time_sld setFloatValue: f_updated];
var_Get( p_input, "time", &time );
mtime_t dur = input_item_GetDuration( input_GetItem( p_input ) );
if( [o_time_fld timeRemaining] && dur != -1 )
{
o_time = [NSString stringWithFormat: @"-%s", secstotimestr( psz_time, ((dur - time.i_time) / 1000000) )];
}
else
o_time = [NSString stringWithUTF8String: secstotimestr( psz_time, (time.i_time / 1000000) )];
[o_time_fld setStringValue: o_time];
[o_fspanel setStreamPos: f_updated andTime: o_time];
vlc_object_release( p_input );
}
}
- (IBAction)volumeAction:(id)sender
{
if (sender == o_volume_sld)
[[VLCCoreInteraction sharedInstance] setVolume: [sender intValue]];
else if (sender == o_volume_down_btn)
{
[[VLCCoreInteraction sharedInstance] mute];
}
else
[[VLCCoreInteraction sharedInstance] setVolume: AOUT_VOLUME_MAX];
}
- (IBAction)effects:(id)sender
{
[[VLCMainMenu sharedInstance] showAudioEffects: sender];
}
- (IBAction)fullscreen:(id)sender
{
[[VLCCoreInteraction sharedInstance] toggleFullscreen];
}
- (IBAction)dropzoneButtonAction:(id)sender
{
[[[VLCMain sharedInstance] open] openFileGeneric];
}
#pragma mark -
#pragma mark overwritten default functionality
- (BOOL)canBecomeKeyWindow
{
return YES;
}
- (BOOL)validateMenuItem:(NSMenuItem *)menuItem
{
SEL s_menuAction = [menuItem action];
if ((s_menuAction == @selector(performClose:)) || (s_menuAction == @selector(performMiniaturize:)) || (s_menuAction == @selector(performZoom:)))
return YES;
return [super validateMenuItem:menuItem];
}
- (void)setTitle:(NSString *)title
{
if (b_dark_interface)
{
[o_titlebar_view setWindowTitle: title];
[o_detached_titlebar_view setWindowTitle: title];
}
if (b_nonembedded && [[VLCMain sharedInstance] activeVideoPlayback])
[o_detached_video_window setTitle: title];
[super setTitle: title];
}
- (void)performClose:(id)sender
{
NSWindow *o_key_window = [NSApp keyWindow];
if (b_dark_interface)
{
[o_key_window orderOut: sender];
if ( [[VLCMain sharedInstance] activeVideoPlayback] && ( !b_nonembedded || o_key_window != self ))
[[VLCCoreInteraction sharedInstance] stop];
}
else
{
if( b_nonembedded && o_key_window != self )
[o_detached_video_window performClose: sender];
else
[super performClose: sender];
}
}
- (void)performMiniaturize:(id)sender
{
if (b_dark_interface)
[self miniaturize: sender];
else
[super performMiniaturize: sender];
}
- (void)performZoom:(id)sender
{
if (b_dark_interface)
[self customZoom: sender];
else
[super performZoom: sender];
}
- (void)zoom:(id)sender
{
if (b_dark_interface)
[self customZoom: sender];
else
[super zoom: sender];
}
/**
* Given a proposed frame rectangle, return a modified version
* which will fit inside the screen.
*
* This method is based upon NSWindow.m, part of the GNUstep GUI Library, licensed under LGPLv2+.
* Authors: Scott Christley <scottc@net-community.com>, Venkat Ajjanagadde <venkat@ocbi.com>,
* Felipe A. Rodriguez <far@ix.netcom.com>, Richard Frith-Macdonald <richard@brainstorm.co.uk>
* Copyright (C) 1996 Free Software Foundation, Inc.
*/
- (NSRect) customConstrainFrameRect: (NSRect)frameRect toScreen: (NSScreen*)screen
{
NSRect screenRect = [screen visibleFrame];
float difference;
/* Move top edge of the window inside the screen */
difference = NSMaxY (frameRect) - NSMaxY (screenRect);
if (difference > 0)
{
frameRect.origin.y -= difference;
}
/* If the window is resizable, resize it (if needed) so that the
bottom edge is on the screen or can be on the screen when the user moves
the window */
difference = NSMaxY (screenRect) - NSMaxY (frameRect);
if (_styleMask & NSResizableWindowMask)
{
float difference2;
difference2 = screenRect.origin.y - frameRect.origin.y;
difference2 -= difference;
// Take in account the space between the top of window and the top of the
// screen which can be used to move the bottom of the window on the screen
if (difference2 > 0)
{
frameRect.size.height -= difference2;
frameRect.origin.y += difference2;
}
/* Ensure that resizing doesn't makewindow smaller than minimum */
difference2 = [self minSize].height - frameRect.size.height;
if (difference2 > 0)
{
frameRect.size.height += difference2;
frameRect.origin.y -= difference2;
}
}
return frameRect;
}
#define DIST 3
/**
Zooms the receiver. This method calls the delegate method
windowShouldZoom:toFrame: to determine if the window should
be allowed to zoom to full screen.
*
* This method is based upon NSWindow.m, part of the GNUstep GUI Library, licensed under LGPLv2+.
* Authors: Scott Christley <scottc@net-community.com>, Venkat Ajjanagadde <venkat@ocbi.com>,
* Felipe A. Rodriguez <far@ix.netcom.com>, Richard Frith-Macdonald <richard@brainstorm.co.uk>
* Copyright (C) 1996 Free Software Foundation, Inc.
*/
- (void)customZoom:(id)sender
{
NSRect maxRect = [[self screen] visibleFrame];
NSRect currentFrame = [self frame];
if ([[self delegate] respondsToSelector: @selector(windowWillUseStandardFrame:defaultFrame:)])
{
maxRect = [[self delegate] windowWillUseStandardFrame: self defaultFrame: maxRect];
}
maxRect = [self customConstrainFrameRect: maxRect toScreen: [self screen]];
// Compare the new frame with the current one
if ((abs(NSMaxX(maxRect) - NSMaxX(currentFrame)) < DIST)
&& (abs(NSMaxY(maxRect) - NSMaxY(currentFrame)) < DIST)
&& (abs(NSMinX(maxRect) - NSMinX(currentFrame)) < DIST)
&& (abs(NSMinY(maxRect) - NSMinY(currentFrame)) < DIST))
{
// Already in zoomed mode, reset user frame, if stored
if ([self frameAutosaveName] != nil)
{
[self setFrame: previousSavedFrame display: YES animate: YES];
[self saveFrameUsingName: [self frameAutosaveName]];
}
return;
}
if ([self frameAutosaveName] != nil)
{
[self saveFrameUsingName: [self frameAutosaveName]];
previousSavedFrame = [self frame];
}
[self setFrame: maxRect display: YES animate: YES];
}
- (void)windowResizedOrMoved:(NSNotification *)notification
{
[self saveFrameUsingName: [self frameAutosaveName]];
}
- (void)applicationWillTerminate:(NSNotification *)notification
{
if( config_GetInt( VLCIntf, "macosx-autosave-volume" ))
config_PutInt( VLCIntf->p_libvlc, "volume", i_lastShownVolume );
[self saveFrameUsingName: [self frameAutosaveName]];
}
- (void)someWindowWillClose:(NSNotification *)notification
{
if([notification object] == o_detached_video_window || ([notification object] == self && !b_nonembedded))
{
if ([[VLCMain sharedInstance] activeVideoPlayback])
[[VLCCoreInteraction sharedInstance] stop];
}
}
- (void)someWindowWillMiniaturize:(NSNotification *)notification
{
if (config_GetInt( VLCIntf, "macosx-pause-minimized" ))
{
if([notification object] == o_detached_video_window || ([notification object] == self && !b_nonembedded))
{
if([[VLCMain sharedInstance] activeVideoPlayback])
[[VLCCoreInteraction sharedInstance] pause];
}
}
}
- (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;
if( [[VLCCoreInteraction sharedInstance] aspectRatioIsLocked] )
{
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;
proposedFrameSize.height = (proposedFrameSize.width - marginx) * nativeVideoSize.height / nativeVideoSize.width + marginy;
}
return proposedFrameSize;
}
#pragma mark -
#pragma mark Update interface and respond to foreign events
- (void)showDropZone
{
b_dropzone_active = YES;
[o_right_split_view addSubview: o_dropzone_view];
[o_dropzone_view setFrame: [o_playlist_table frame]];
[[o_playlist_table animator] setHidden:YES];
}
- (void)hideDropZone
{
[o_dropzone_view removeFromSuperview];
[[o_playlist_table animator] setHidden: NO];
}
- (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];
if (b_dark_interface)
{
[self setContentMinSize: NSMakeSize( 604., [o_bottombar_view frame].size.height + [o_titlebar_view frame].size.height )];
[self setContentMaxSize: NSMakeSize( FLT_MAX, [o_bottombar_view frame].size.height + [o_titlebar_view frame].size.height )];
}
else
{
[self setContentMinSize: NSMakeSize( 604., [o_bottombar_view frame].size.height )];
[self setContentMaxSize: NSMakeSize( FLT_MAX, [o_bottombar_view frame].size.height )];
}
if (i_lastSplitViewHeight < 100)
i_lastSplitViewHeight = 300; // random reasonable size
b_splitview_removed = YES;
}
- (void)showSplitView
{
[self updateWindow];
if (b_dark_interface)
[self setContentMinSize:NSMakeSize( 604., 288. + [o_titlebar_view frame].size.height )];
else
[self setContentMinSize:NSMakeSize( 604., 288. )];
[self setContentMaxSize: NSMakeSize( FLT_MAX, FLT_MAX )];
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;
}
- (void)updateTimeSlider
{
input_thread_t * p_input;
p_input = pl_CurrentInput( VLCIntf );
if( p_input )
{
vlc_value_t time;
NSString * o_time;
vlc_value_t pos;
char psz_time[MSTRTIME_MAX_SIZE];
float f_updated;
var_Get( p_input, "position", &pos );
f_updated = 10000. * pos.f_float;
[o_time_sld setFloatValue: f_updated];
var_Get( p_input, "time", &time );
mtime_t dur = input_item_GetDuration( input_GetItem( p_input ) );
if( [o_time_fld timeRemaining] && dur != -1 )
{
o_time = [NSString stringWithFormat: @"-%s", secstotimestr( psz_time, ((dur - time.i_time) / 1000000))];
}
else
o_time = [NSString stringWithUTF8String: secstotimestr( psz_time, (time.i_time / 1000000) )];
if (dur == -1) {
[o_time_sld setEnabled: NO];
[o_time_sld setHidden: YES];
[o_time_sld_fancygradient_view setHidden: YES];
} else {
[o_time_sld setEnabled: YES];
[o_time_sld setHidden: NO];
[o_time_sld_fancygradient_view setHidden: NO];
}
[o_time_fld setStringValue: o_time];
[o_time_fld setNeedsDisplay:YES];
[o_fspanel setStreamPos: f_updated andTime: o_time];
vlc_object_release( p_input );
}
else
{
[o_time_sld setFloatValue: 0.0];
[o_time_fld setStringValue: @"00:00"];
[o_time_sld setEnabled: NO];
[o_time_sld setHidden: YES];
[o_time_sld_fancygradient_view setHidden: YES];
[o_detached_time_sld_fancygradient_view setHidden: YES];
}
[o_detached_time_sld setFloatValue: [o_time_sld floatValue]];
[o_detached_time_sld setEnabled: [o_time_sld isEnabled]];
[o_detached_time_fld setStringValue: [o_time_fld stringValue]];
[o_detached_time_sld setHidden: [o_time_sld isHidden]];
}
- (void)updateVolumeSlider
{
audio_volume_t i_volume;
playlist_t * p_playlist = pl_Get( VLCIntf );
i_volume = aout_VolumeGet( p_playlist );
BOOL b_muted = [[VLCCoreInteraction sharedInstance] isMuted];
if( !b_muted )
{
i_lastShownVolume = i_volume;
[o_volume_sld setIntValue: i_volume];
[o_fspanel setVolumeLevel: i_volume];
}
else
[o_volume_sld setIntValue: 0];
[o_volume_sld setEnabled: !b_muted];
[o_volume_up_btn setEnabled: !b_muted];
}
- (void)updateName
{
NSAutoreleasePool *o_pool = [[NSAutoreleasePool alloc] init];
input_thread_t * p_input;
p_input = pl_CurrentInput( VLCIntf );
if( p_input )
{
NSString *aString;
char *format = var_InheritString( VLCIntf, "input-title-format" );
char *formated = str_format_meta( p_input, format );
free( format );
aString = [NSString stringWithUTF8String:formated];
free( formated );
char *uri = input_item_GetURI( input_GetItem( p_input ) );
NSURL * o_url = [NSURL URLWithString: [NSString stringWithUTF8String: uri]];
if ([o_url isFileURL])
[self setRepresentedURL: o_url];
else
[self setRepresentedURL: nil];
free( uri );
if ([aString isEqualToString:@""])
{
if ([o_url isFileURL])
aString = [[NSFileManager defaultManager] displayNameAtPath: [o_url path]];
else
aString = [o_url absoluteString];
}
[self setTitle: aString];
[o_fspanel setStreamTitle: aString];
vlc_object_release( p_input );
}
else
{
[self setTitle: _NS("VLC media player")];
[self setRepresentedURL: nil];
}
[o_pool release];
}
- (void)updateWindow
{
bool b_input = false;
bool b_plmul = false;
bool b_control = false;
bool b_seekable = false;
bool b_chapters = false;
playlist_t * p_playlist = pl_Get( VLCIntf );
PL_LOCK;
b_plmul = playlist_CurrentSize( p_playlist ) > 1;
PL_UNLOCK;
input_thread_t * p_input = playlist_CurrentInput( p_playlist );
bool b_buffering = NO;
if( ( b_input = ( p_input != NULL ) ) )
{
/* seekable streams */
cachedInputState = input_GetState( p_input );
if ( cachedInputState == INIT_S || cachedInputState == OPENING_S )
b_buffering = YES;
/* seekable streams */
b_seekable = var_GetBool( p_input, "can-seek" );
/* check whether slow/fast motion is possible */
b_control = var_GetBool( p_input, "can-rate" );
/* chapters & titles */
//FIXME! b_chapters = p_input->stream.i_area_nb > 1;
if (( cachedInputState == PLAYING_S || b_buffering == YES ) && [[VLCMain sharedInstance] activeVideoPlayback] )
[[o_video_view window] makeKeyAndOrderFront: nil];
vlc_object_release( p_input );
}
if( b_buffering )
{
[o_progress_bar startAnimation:self];
[o_progress_bar setIndeterminate:YES];
[o_progress_bar setHidden:NO];
} else {
[o_progress_bar stopAnimation:self];
[o_progress_bar setHidden:YES];
}
[o_stop_btn setEnabled: b_input];
[o_fwd_btn setEnabled: (b_seekable || b_plmul || b_chapters)];
[o_bwd_btn setEnabled: (b_seekable || b_plmul || b_chapters)];
[o_detached_fwd_btn setEnabled: (b_seekable || b_plmul || b_chapters)];
[o_detached_bwd_btn setEnabled: (b_seekable || b_plmul || b_chapters)];
[[VLCMainMenu sharedInstance] setRateControlsEnabled: b_control];
[o_time_sld setEnabled: b_seekable];
[self updateTimeSlider];
[o_fspanel setSeekable: b_seekable];
PL_LOCK;
if ([[[VLCMain sharedInstance] playlist] currentPlaylistRoot] != p_playlist->p_local_category || p_playlist->p_local_category->i_children > 0)
[self hideDropZone];
else
[self showDropZone];
PL_UNLOCK;
[o_sidebar_view setNeedsDisplay:YES];
}
- (void)setPause
{
[o_play_btn setImage: o_pause_img];
[o_play_btn setAlternateImage: o_pause_pressed_img];
[o_play_btn setToolTip: _NS("Pause")];
[o_detached_play_btn setImage: o_pause_img];
[o_detached_play_btn setAlternateImage: o_pause_pressed_img];
[o_detached_play_btn setToolTip: _NS("Pause")];
[o_fspanel setPause];
}
- (void)setPlay
{
[o_play_btn setImage: o_play_img];
[o_play_btn setAlternateImage: o_play_pressed_img];
[o_play_btn setToolTip: _NS("Play")];
[o_detached_play_btn setImage: o_play_img];
[o_detached_play_btn setAlternateImage: o_play_pressed_img];
[o_detached_play_btn setToolTip: _NS("Play")];
[o_fspanel setPlay];
}
- (void)drawFancyGradientEffectForTimeSlider
{
if (OSX_LEOPARD)
return;
NSAutoreleasePool * o_pool = [[NSAutoreleasePool alloc] init];
CGFloat f_value = [o_time_sld knobPosition];
if (f_value > 7.5)
{
NSRect oldFrame = [o_time_sld_fancygradient_view frame];
if (f_value != oldFrame.size.width)
{
if ([o_time_sld_fancygradient_view isHidden])
[o_time_sld_fancygradient_view setHidden: NO];
[o_time_sld_fancygradient_view setFrame: NSMakeRect( oldFrame.origin.x, oldFrame.origin.y, f_value, oldFrame.size.height )];
}
if (b_nonembedded)
{
f_value = [o_detached_time_sld knobPosition];
oldFrame = [o_detached_time_sld_fancygradient_view frame];
if (f_value != oldFrame.size.width)
{
if ([o_detached_time_sld_fancygradient_view isHidden])
[o_detached_time_sld_fancygradient_view setHidden: NO];
[o_detached_time_sld_fancygradient_view setFrame: NSMakeRect( oldFrame.origin.x, oldFrame.origin.y, f_value, oldFrame.size.height )];
}
}
}
else
{
NSRect frame;
frame = [o_time_sld_fancygradient_view frame];
if (frame.size.width > 0)
{
frame.size.width = 0;
[o_time_sld_fancygradient_view setFrame: frame];
frame = [o_detached_time_sld_fancygradient_view frame];
frame.size.width = 0;
[o_detached_time_sld_fancygradient_view setFrame: frame];
}
[o_time_sld_fancygradient_view setHidden: YES];
[o_detached_time_sld_fancygradient_view setHidden: YES];
}
[o_pool release];
}
#pragma mark -
#pragma mark Video Output handling
- (id)videoView
{
return o_video_view;
}
- (id)setupVideoView
{
vout_thread_t *p_vout = getVout();
if (config_GetInt( VLCIntf, "embedded-video" ) || b_nativeFullscreenMode)
{
if ([o_video_view window] != self)
{
[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;
}
else
{
if ([o_video_view superview] != NULL)
[o_video_view removeFromSuperviewWithoutNeedingDisplay];
NSRect frame = [o_detached_video_window frame];
NSRect videoFrame = [o_video_view frame];
frame.size.width = videoFrame.size.width;
frame.size.height = videoFrame.size.height + [o_detached_bottombar_view frame].size.height + [o_titlebar_view frame].size.height;
[o_detached_video_window setFrame: frame display: NO];
[[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];
[o_detached_video_window center];
b_nonembedded = YES;
}
[[o_video_view window] makeKeyAndOrderFront: self];
[[o_video_view window] setAlphaValue: config_GetFloat( VLCIntf, "macosx-opaqueness" )];
if (p_vout)
{
if( var_GetBool( p_vout, "video-on-top" ) )
[[o_video_view window] setLevel: NSStatusWindowLevel];
else
[[o_video_view window] setLevel: NSNormalWindowLevel];
vlc_object_release( p_vout );
}
return o_video_view;
}
- (void)setVideoplayEnabled
{
BOOL b_videoPlayback = [[VLCMain sharedInstance] activeVideoPlayback];
if (!b_videoPlayback)
{
[o_detached_video_window orderOut: nil];
// restore alpha value to 1 for the case that macosx-opaqueness is set to < 1
[self setAlphaValue:1.0];
}
if( b_nativeFullscreenMode )
{
if( [NSApp presentationOptions] & NSApplicationPresentationFullScreen )
[o_bottombar_view setHidden: b_videoPlayback];
else
[o_bottombar_view setHidden: NO];
if (!b_videoPlayback)
[o_fspanel setNonActive: nil];
}
if (b_videoPlayback)
[self makeFirstResponder: o_video_view];
else
[self makeFirstResponder: nil];
if (!b_videoPlayback && b_fullscreen)
{
if (!b_nativeFullscreenMode)
[[VLCCoreInteraction sharedInstance] toggleFullscreen];
}
}
- (void)resizeWindow
{
if ( b_fullscreen || (b_nativeFullscreenMode && [NSApp presentationOptions] & NSApplicationPresentationFullScreen ))
return;
NSPoint topleftbase = NSMakePoint(0, [self frame].size.height);
NSPoint topleftscreen = [self convertBaseToScreen: topleftbase];
/* Calculate the window's new size */
float w = [self frame].size.width - [o_video_view frame].size.width
+ nativeVideoSize.width;
float h = [self frame].size.height - [o_video_view frame].size.height
+ nativeVideoSize.height;
if (b_dark_interface)
h += [o_titlebar_view frame].size.height;
NSRect new_frame = NSMakeRect(topleftscreen.x, topleftscreen.y - h, w, h);
[[self animator] setFrame:new_frame display:YES];
}
- (void)setNativeVideoSize:(NSSize)size
{
if (size.width != nativeVideoSize.width || size.height != nativeVideoSize.height )
{
nativeVideoSize = size;
[self resizeWindow];
}
}
// Called automatically if window's acceptsMouseMovedEvents property is true
- (void)mouseMoved:(NSEvent *)theEvent
{
if (b_fullscreen)
[self recreateHideMouseTimer];
[super mouseMoved: theEvent];
}
- (void)recreateHideMouseTimer
{
if (t_hide_mouse_timer != nil) {
[t_hide_mouse_timer invalidate];
[t_hide_mouse_timer release];
}
t_hide_mouse_timer = [NSTimer scheduledTimerWithTimeInterval:2
target:self
selector:@selector(hideMouseCursor:)
userInfo:nil
repeats:NO];
[t_hide_mouse_timer retain];
}
// NSTimer selectors require this function signature as per Apple's docs
- (void)hideMouseCursor:(NSTimer *)timer
{
[NSCursor setHiddenUntilMouseMoves: YES];
}
#pragma mark -
#pragma mark Fullscreen support
- (void)showFullscreenController
{
if (b_fullscreen && [[VLCMain sharedInstance] activeVideoPlayback] )
[o_fspanel fadeIn];
}
- (void)updateFullscreen
{
[[VLCMain sharedInstance] fullscreenChanged];
}
- (BOOL)isFullscreen
{
return b_fullscreen;
}
- (void)lockFullscreenAnimation
{
[o_animation_lock lock];
}
- (void)unlockFullscreenAnimation
{
[o_animation_lock unlock];
}
- (void)enterFullscreen
{
NSMutableDictionary *dict1, *dict2;
NSScreen *screen;
NSRect screen_rect;
NSRect rect;
vout_thread_t *p_vout = getVout();
BOOL blackout_other_displays = config_GetInt( VLCIntf, "macosx-black" );
id o_videoWindow = b_nonembedded ? o_detached_video_window : self;
if( p_vout )
screen = [NSScreen screenWithDisplayID:(CGDirectDisplayID)config_GetInt( VLCIntf, "macosx-vdev" )];
[self lockFullscreenAnimation];
if (!screen)
{
msg_Dbg( VLCIntf, "chosen screen isn't present, using current screen for fullscreen mode" );
screen = [o_videoWindow screen];
}
if (!screen)
{
msg_Dbg( VLCIntf, "Using deepest screen" );
screen = [NSScreen deepestScreen];
}
if( p_vout )
vlc_object_release( p_vout );
screen_rect = [screen frame];
[o_fullscreen_btn setState: YES];
[o_detached_fullscreen_btn setState: YES];
[self recreateHideMouseTimer];
if( blackout_other_displays )
[screen blackoutOtherScreens];
/* Make sure we don't see the window flashes in float-on-top mode */
i_originalLevel = [o_videoWindow level];
[o_videoWindow setLevel:NSNormalWindowLevel];
/* Only create the o_fullscreen_window if we are not in the middle of the zooming animation */
if (!o_fullscreen_window)
{
/* We can't change the styleMask of an already created NSWindow, so we create another window, and do eye catching stuff */
rect = [[o_video_view superview] convertRect: [o_video_view frame] toView: nil]; /* Convert to Window base coord */
rect.origin.x += [o_videoWindow frame].origin.x;
rect.origin.y += [o_videoWindow frame].origin.y;
o_fullscreen_window = [[VLCWindow alloc] initWithContentRect:rect styleMask: NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:YES];
[o_fullscreen_window setFullscreen: YES];
[o_fullscreen_window setBackgroundColor: [NSColor blackColor]];
[o_fullscreen_window setCanBecomeKeyWindow: YES];
if (![o_videoWindow isVisible] || [o_videoWindow alphaValue] == 0.0)
{
/* We don't animate if we are not visible, instead we
* simply fade the display */
CGDisplayFadeReservationToken token;
if( blackout_other_displays )
{
CGAcquireDisplayFadeReservation( kCGMaxDisplayReservationInterval, &token );
CGDisplayFade( token, 0.5, kCGDisplayBlendNormal, kCGDisplayBlendSolidColor, 0, 0, 0, YES );
}
if ([screen isMainScreen])
{
if (OSX_LEOPARD)
SetSystemUIMode( kUIModeAllHidden, kUIOptionAutoShowMenuBar);
else
[NSApp setPresentationOptions:(NSApplicationPresentationAutoHideDock | NSApplicationPresentationAutoHideMenuBar)];
}
[[o_video_view superview] replaceSubview:o_video_view with:o_temp_view];
[o_temp_view setFrame:[o_video_view frame]];
[o_fullscreen_window setContentView:o_video_view];
[o_fullscreen_window makeKeyAndOrderFront:self];
[o_fullscreen_window orderFront:self animate:YES];
[o_fullscreen_window setFrame:screen_rect display:YES animate:YES];
[o_fullscreen_window setLevel:NSNormalWindowLevel];
if( blackout_other_displays )
{
CGDisplayFade( token, 0.3, kCGDisplayBlendSolidColor, kCGDisplayBlendNormal, 0, 0, 0, NO );
CGReleaseDisplayFadeReservation( token );
}
/* Will release the lock */
[self hasBecomeFullscreen];
return;
}
/* Make sure we don't see the o_video_view disappearing of the screen during this operation */
NSDisableScreenUpdates();
[[o_video_view superview] replaceSubview:o_video_view with:o_temp_view];
[o_temp_view setFrame:[o_video_view frame]];
[o_fullscreen_window setContentView:o_video_view];
[o_fullscreen_window makeKeyAndOrderFront:self];
NSEnableScreenUpdates();
}
/* We are in fullscreen (and no animation is running) */
if (b_fullscreen)
{
/* Make sure we are hidden */
[o_videoWindow orderOut: self];
[self unlockFullscreenAnimation];
return;
}
if (o_fullscreen_anim1)
{
[o_fullscreen_anim1 stopAnimation];
[o_fullscreen_anim1 release];
}
if (o_fullscreen_anim2)
{
[o_fullscreen_anim2 stopAnimation];
[o_fullscreen_anim2 release];
}
if ([screen isMainScreen])
{
if (OSX_LEOPARD)
SetSystemUIMode( kUIModeAllHidden, kUIOptionAutoShowMenuBar);
else
[NSApp setPresentationOptions:(NSApplicationPresentationAutoHideDock | NSApplicationPresentationAutoHideMenuBar)];
}
dict1 = [[NSMutableDictionary alloc] initWithCapacity:2];
dict2 = [[NSMutableDictionary alloc] initWithCapacity:3];
[dict1 setObject:o_videoWindow forKey:NSViewAnimationTargetKey];
[dict1 setObject:NSViewAnimationFadeOutEffect forKey:NSViewAnimationEffectKey];
[dict2 setObject:o_fullscreen_window forKey:NSViewAnimationTargetKey];
[dict2 setObject:[NSValue valueWithRect:[o_fullscreen_window frame]] forKey:NSViewAnimationStartFrameKey];
[dict2 setObject:[NSValue valueWithRect:screen_rect] forKey:NSViewAnimationEndFrameKey];
/* Strategy with NSAnimation allocation:
- Keep at most 2 animation at a time
- leaveFullscreen/enterFullscreen are the only responsible for releasing and alloc-ing
*/
o_fullscreen_anim1 = [[NSViewAnimation alloc] initWithViewAnimations:[NSArray arrayWithObject:dict1]];
o_fullscreen_anim2 = [[NSViewAnimation alloc] initWithViewAnimations:[NSArray arrayWithObject:dict2]];
[dict1 release];
[dict2 release];
[o_fullscreen_anim1 setAnimationBlockingMode: NSAnimationNonblocking];
[o_fullscreen_anim1 setDuration: 0.3];
[o_fullscreen_anim1 setFrameRate: 30];
[o_fullscreen_anim2 setAnimationBlockingMode: NSAnimationNonblocking];
[o_fullscreen_anim2 setDuration: 0.2];
[o_fullscreen_anim2 setFrameRate: 30];
[o_fullscreen_anim2 setDelegate: self];
[o_fullscreen_anim2 startWhenAnimation: o_fullscreen_anim1 reachesProgress: 1.0];
[o_fullscreen_anim1 startAnimation];
/* fullscreenAnimation will be unlocked when animation ends */
}
- (void)hasBecomeFullscreen
{
[o_fullscreen_window makeFirstResponder: o_video_view];
[o_fullscreen_window makeKeyWindow];
[o_fullscreen_window setAcceptsMouseMovedEvents: TRUE];
/* tell the fspanel to move itself to front next time it's triggered */
[o_fspanel setVoutWasUpdated: (int)[[o_fullscreen_window screen] displayID]];
[o_fspanel setActive: nil];
id o_videoWindow = b_nonembedded ? o_detached_video_window : self;
if( [o_videoWindow isVisible] )
[o_videoWindow orderOut: self];
[o_fspanel setActive: nil];
b_fullscreen = YES;
[self unlockFullscreenAnimation];
}
- (void)leaveFullscreen
{
[self leaveFullscreenAndFadeOut: NO];
}
- (void)leaveFullscreenAndFadeOut: (BOOL)fadeout
{
NSMutableDictionary *dict1, *dict2;
NSRect frame;
BOOL blackout_other_displays = config_GetInt( VLCIntf, "macosx-black" );
[self lockFullscreenAnimation];
b_fullscreen = NO;
[o_fullscreen_btn setState: NO];
[o_detached_fullscreen_btn setState: NO];
/* We always try to do so */
[NSScreen unblackoutScreens];
vout_thread_t *p_vout = getVout();
if (p_vout)
{
if( var_GetBool( p_vout, "video-on-top" ) )
[[o_video_view window] setLevel: NSStatusWindowLevel];
else
[[o_video_view window] setLevel: NSNormalWindowLevel];
vlc_object_release( p_vout );
}
[[o_video_view window] makeKeyAndOrderFront: nil];
/* Don't do anything if o_fullscreen_window is already closed */
if (!o_fullscreen_window)
{
[self unlockFullscreenAnimation];
return;
}
if (fadeout)
{
/* We don't animate if we are not visible, instead we
* simply fade the display */
CGDisplayFadeReservationToken token;
if( blackout_other_displays )
{
CGAcquireDisplayFadeReservation( kCGMaxDisplayReservationInterval, &token );
CGDisplayFade( token, 0.3, kCGDisplayBlendNormal, kCGDisplayBlendSolidColor, 0, 0, 0, YES );
}
[o_fspanel setNonActive: nil];
if (OSX_LEOPARD)
SetSystemUIMode( kUIModeNormal, kUIOptionAutoShowMenuBar);
else
[NSApp setPresentationOptions: NSApplicationPresentationDefault];
/* Will release the lock */
[self hasEndedFullscreen];
/* Our window is hidden, and might be faded. We need to workaround that, so note it
* here */
b_window_is_invisible = YES;
if( blackout_other_displays )
{
CGDisplayFade( token, 0.5, kCGDisplayBlendSolidColor, kCGDisplayBlendNormal, 0, 0, 0, NO );
CGReleaseDisplayFadeReservation( token );
}
return;
}
id o_videoWindow = b_nonembedded ? o_detached_video_window : self;
[o_videoWindow setAlphaValue: 0.0];
[o_videoWindow orderFront: self];
[[o_video_view window] orderFront: self];
[o_fspanel setNonActive: nil];
if (OSX_LEOPARD)
SetSystemUIMode( kUIModeNormal, kUIOptionAutoShowMenuBar);
else
[NSApp setPresentationOptions:(NSApplicationPresentationDefault)];
if (o_fullscreen_anim1)
{
[o_fullscreen_anim1 stopAnimation];
[o_fullscreen_anim1 release];
}
if (o_fullscreen_anim2)
{
[o_fullscreen_anim2 stopAnimation];
[o_fullscreen_anim2 release];
}
frame = [[o_temp_view superview] convertRect: [o_temp_view frame] toView: nil]; /* Convert to Window base coord */
frame.origin.x += [o_videoWindow frame].origin.x;
frame.origin.y += [o_videoWindow frame].origin.y;
dict2 = [[NSMutableDictionary alloc] initWithCapacity:2];
[dict2 setObject:o_videoWindow forKey:NSViewAnimationTargetKey];
[dict2 setObject:NSViewAnimationFadeInEffect forKey:NSViewAnimationEffectKey];
o_fullscreen_anim2 = [[NSViewAnimation alloc] initWithViewAnimations:[NSArray arrayWithObjects:dict2, nil]];
[dict2 release];
[o_fullscreen_anim2 setAnimationBlockingMode: NSAnimationNonblocking];
[o_fullscreen_anim2 setDuration: 0.3];
[o_fullscreen_anim2 setFrameRate: 30];
[o_fullscreen_anim2 setDelegate: self];
dict1 = [[NSMutableDictionary alloc] initWithCapacity:3];
[dict1 setObject:o_fullscreen_window forKey:NSViewAnimationTargetKey];
[dict1 setObject:[NSValue valueWithRect:[o_fullscreen_window frame]] forKey:NSViewAnimationStartFrameKey];
[dict1 setObject:[NSValue valueWithRect:frame] forKey:NSViewAnimationEndFrameKey];
o_fullscreen_anim1 = [[NSViewAnimation alloc] initWithViewAnimations:[NSArray arrayWithObjects:dict1, nil]];
[dict1 release];
[o_fullscreen_anim1 setAnimationBlockingMode: NSAnimationNonblocking];
[o_fullscreen_anim1 setDuration: 0.2];
[o_fullscreen_anim1 setFrameRate: 30];
[o_fullscreen_anim2 startWhenAnimation: o_fullscreen_anim1 reachesProgress: 1.0];
/* Make sure o_fullscreen_window is the frontmost window */
[o_fullscreen_window orderFront: self];
[o_fullscreen_anim1 startAnimation];
/* fullscreenAnimation will be unlocked when animation ends */
}
- (void)hasEndedFullscreen
{
/* This function is private and should be only triggered at the end of the fullscreen change animation */
/* Make sure we don't see the o_video_view disappearing of the screen during this operation */
NSDisableScreenUpdates();
[o_video_view retain];
[o_video_view removeFromSuperviewWithoutNeedingDisplay];
[[o_temp_view superview] replaceSubview:o_temp_view with:o_video_view];
[o_video_view release];
[o_video_view setFrame:[o_temp_view frame]];
[[o_video_view window] makeFirstResponder: o_video_view];
if( [[o_video_view window] isVisible] )
{
if( !b_nonembedded )
[super makeKeyAndOrderFront:self]; /* our version contains a workaround */
else
[[o_video_view window] makeKeyAndOrderFront: self];
}
[o_fullscreen_window orderOut: self];
NSEnableScreenUpdates();
[o_fullscreen_window release];
o_fullscreen_window = nil;
[[o_video_view window] setLevel:i_originalLevel];
[[o_video_view window] setAlphaValue: config_GetFloat( VLCIntf, "macosx-opaqueness" )];
// if we quit fullscreen because there is no video anymore, make sure non-embedded window is not visible
if( ![[VLCMain sharedInstance] activeVideoPlayback] && b_nonembedded )
[o_detached_video_window orderOut: self];
[self unlockFullscreenAnimation];
}
- (void)animationDidEnd:(NSAnimation*)animation
{
NSArray *viewAnimations;
if( o_makekey_anim == animation )
{
[o_makekey_anim release];
return;
}
if ([animation currentValue] < 1.0)
return;
/* Fullscreen ended or started (we are a delegate only for leaveFullscreen's/enterFullscren's anim2) */
viewAnimations = [o_fullscreen_anim2 viewAnimations];
if ([viewAnimations count] >=1 &&
[[[viewAnimations objectAtIndex: 0] objectForKey: NSViewAnimationEffectKey] isEqualToString:NSViewAnimationFadeInEffect])
{
/* Fullscreen ended */
[self hasEndedFullscreen];
}
else
{
/* Fullscreen started */
[self hasBecomeFullscreen];
}
}
- (void)makeKeyAndOrderFront: (id)sender
{
/* Hack
* when we exit fullscreen and fade out, we may endup in
* having a window that is faded. We can't have it fade in unless we
* animate again. */
if(!b_window_is_invisible)
{
/* Make sure we don't do it too much */
[super makeKeyAndOrderFront: sender];
return;
}
[super setAlphaValue:0.0f];
[super makeKeyAndOrderFront: sender];
NSMutableDictionary * dict = [[NSMutableDictionary alloc] initWithCapacity:2];
[dict setObject:self forKey:NSViewAnimationTargetKey];
[dict setObject:NSViewAnimationFadeInEffect forKey:NSViewAnimationEffectKey];
o_makekey_anim = [[NSViewAnimation alloc] initWithViewAnimations:[NSArray arrayWithObject:dict]];
[dict release];
[o_makekey_anim setAnimationBlockingMode: NSAnimationNonblocking];
[o_makekey_anim setDuration: 0.1];
[o_makekey_anim setFrameRate: 30];
[o_makekey_anim setDelegate: self];
[o_makekey_anim startAnimation];
b_window_is_invisible = NO;
/* fullscreenAnimation will be unlocked when animation ends */
}
#pragma mark -
#pragma mark Lion's native fullscreen handling
- (void)windowWillEnterFullScreen:(NSNotification *)notification
{
[o_video_view setFrame: [[self contentView] frame]];
b_fullscreen = YES;
[o_fspanel setVoutWasUpdated: (int)[[self screen] displayID]];
[o_fspanel setActive: nil];
[self recreateHideMouseTimer];
i_originalLevel = [self level];
[self setLevel:NSNormalWindowLevel];
if (b_dark_interface)
{
[o_titlebar_view removeFromSuperviewWithoutNeedingDisplay];
NSRect winrect;
CGFloat f_titleBarHeight = [o_titlebar_view frame].size.height;
winrect = [self frame];
winrect.size.height = winrect.size.height - f_titleBarHeight;
[self setFrame: winrect display:NO animate:NO];
winrect = [o_split_view frame];
winrect.size.height = winrect.size.height + f_titleBarHeight;
[o_split_view setFrame: winrect];
}
if ([[VLCMain sharedInstance] activeVideoPlayback])
[o_bottombar_view setHidden: YES];
}
- (void)windowWillExitFullScreen:(NSNotification *)notification
{
[o_video_view setFrame: [o_split_view frame]];
[NSCursor setHiddenUntilMouseMoves: NO];
[o_fspanel setNonActive: nil];
[self setLevel:i_originalLevel];
b_fullscreen = NO;
if (b_dark_interface)
{
NSRect winrect;
CGFloat f_titleBarHeight = [o_titlebar_view frame].size.height;
winrect = [self frame];
[o_titlebar_view setFrame: NSMakeRect( 0, winrect.size.height - f_titleBarHeight,
winrect.size.width, f_titleBarHeight )];
[[self contentView] addSubview: o_titlebar_view];
winrect.size.height = winrect.size.height + f_titleBarHeight;
[self setFrame: winrect display:NO animate:NO];
winrect = [o_split_view frame];
winrect.size.height = winrect.size.height - f_titleBarHeight;
[o_split_view setFrame: winrect];
[o_video_view setFrame: winrect];
}
if ([[VLCMain sharedInstance] activeVideoPlayback])
[o_bottombar_view setHidden: NO];
}
#pragma mark -
#pragma mark split view delegate
- (CGFloat)splitView:(NSSplitView *)splitView constrainMaxCoordinate:(CGFloat)proposedMax ofSubviewAt:(NSInteger)dividerIndex
{
if (dividerIndex == 0)
return ([self frame].size.width - 400.0);
else
return proposedMax;
}
#pragma mark -
#pragma mark Side Bar Data handling
/* taken under BSD-new from the PXSourceList sample project, adapted for VLC */
- (NSUInteger)sourceList:(PXSourceList*)sourceList numberOfChildrenOfItem:(id)item
{
//Works the same way as the NSOutlineView data source: `nil` means a parent item
if(item==nil)
return [o_sidebaritems count];
else
return [[item children] count];
}
- (id)sourceList:(PXSourceList*)aSourceList child:(NSUInteger)index ofItem:(id)item
{
//Works the same way as the NSOutlineView data source: `nil` means a parent item
if(item==nil)
return [o_sidebaritems objectAtIndex:index];
else
return [[item children] objectAtIndex:index];
}
- (id)sourceList:(PXSourceList*)aSourceList objectValueForItem:(id)item
{
return [item title];
}
- (void)sourceList:(PXSourceList*)aSourceList setObjectValue:(id)object forItem:(id)item
{
[item setTitle:object];
}
- (BOOL)sourceList:(PXSourceList*)aSourceList isItemExpandable:(id)item
{
return [item hasChildren];
}
- (BOOL)sourceList:(PXSourceList*)aSourceList itemHasBadge:(id)item
{
if ([[item identifier] isEqualToString: @"playlist"] || [[item identifier] isEqualToString: @"medialibrary"])
return YES;
return [item hasBadge];
}
- (NSInteger)sourceList:(PXSourceList*)aSourceList badgeValueForItem:(id)item
{
playlist_t * p_playlist = pl_Get( VLCIntf );
NSInteger i_playlist_size;
if ([[item identifier] isEqualToString: @"playlist"])
{
PL_LOCK;
i_playlist_size = p_playlist->p_local_category->i_children;
PL_UNLOCK;
return i_playlist_size;
}
if ([[item identifier] isEqualToString: @"medialibrary"])
{
PL_LOCK;
i_playlist_size = p_playlist->p_ml_category->i_children;
PL_UNLOCK;
return i_playlist_size;
}
return [item badgeValue];
}
- (BOOL)sourceList:(PXSourceList*)aSourceList itemHasIcon:(id)item
{
return [item hasIcon];
}
- (NSImage*)sourceList:(PXSourceList*)aSourceList iconForItem:(id)item
{
return [item icon];
}
- (NSMenu*)sourceList:(PXSourceList*)aSourceList menuForEvent:(NSEvent*)theEvent item:(id)item
{
if ([theEvent type] == NSRightMouseDown || ([theEvent type] == NSLeftMouseDown && ([theEvent modifierFlags] & NSControlKeyMask) == NSControlKeyMask))
{
if (item != nil)
{
NSMenu * m;
if ([item sdtype] > 0)
{
m = [[NSMenu alloc] init];
playlist_t * p_playlist = pl_Get( VLCIntf );
BOOL sd_loaded = playlist_IsServicesDiscoveryLoaded( p_playlist, [[item identifier] UTF8String] );
if (!sd_loaded)
[m addItemWithTitle:_NS("Enable") action:@selector(sdmenuhandler:) keyEquivalent:@""];
else
[m addItemWithTitle:_NS("Disable") action:@selector(sdmenuhandler:) keyEquivalent:@""];
[[m itemAtIndex:0] setRepresentedObject: [item identifier]];
}
return [m autorelease];
}
}
return nil;
}
- (IBAction)sdmenuhandler:(id)sender
{
NSString * identifier = [sender representedObject];
if ([identifier length] > 0 && ![identifier isEqualToString:@"lua{sd='freebox',longname='Freebox TV'}"])
{
playlist_t * p_playlist = pl_Get( VLCIntf );
BOOL sd_loaded = playlist_IsServicesDiscoveryLoaded( p_playlist, [identifier UTF8String] );
if (!sd_loaded)
playlist_ServicesDiscoveryAdd( p_playlist, [identifier UTF8String] );
else
playlist_ServicesDiscoveryRemove( p_playlist, [identifier UTF8String] );
}
}
#pragma mark -
#pragma mark Side Bar Delegate Methods
/* taken under BSD-new from the PXSourceList sample project, adapted for VLC */
- (BOOL)sourceList:(PXSourceList*)aSourceList isGroupAlwaysExpanded:(id)group
{
if ([[group identifier] isEqualToString:@"library"])
return YES;
return NO;
}
- (void)sourceListSelectionDidChange:(NSNotification *)notification
{
playlist_t * p_playlist = pl_Get( VLCIntf );
NSIndexSet *selectedIndexes = [o_sidebar_view selectedRowIndexes];
id item = [o_sidebar_view itemAtRow:[selectedIndexes firstIndex]];
//Set the label text to represent the new selection
if ([item sdtype] > -1 && [[item identifier] length] > 0)
{
BOOL sd_loaded = playlist_IsServicesDiscoveryLoaded( p_playlist, [[item identifier] UTF8String] );
if (!sd_loaded)
{
playlist_ServicesDiscoveryAdd( p_playlist, [[item identifier] UTF8String] );
}
}
[o_chosen_category_lbl setStringValue:[item title]];
if ([[item identifier] isEqualToString:@"playlist"])
{
[[[VLCMain sharedInstance] playlist] setPlaylistRoot:p_playlist->p_local_category];
}
else if([[item identifier] isEqualToString:@"medialibrary"])
{
[[[VLCMain sharedInstance] playlist] setPlaylistRoot:p_playlist->p_ml_category];
}
else
{
playlist_item_t * pl_item;
PL_LOCK;
pl_item = playlist_ChildSearchName( p_playlist->p_root, [[item untranslatedTitle] UTF8String] );
PL_UNLOCK;
[[[VLCMain sharedInstance] playlist] setPlaylistRoot: pl_item];
}
PL_LOCK;
if ([[[VLCMain sharedInstance] playlist] currentPlaylistRoot] != p_playlist->p_local_category || p_playlist->p_local_category->i_children > 0)
[self hideDropZone];
else
[self showDropZone];
PL_UNLOCK;
}
- (NSDragOperation)sourceList:(PXSourceList *)aSourceList validateDrop:(id <NSDraggingInfo>)info proposedItem:(id)item proposedChildIndex:(NSInteger)index
{
if ([[item identifier] isEqualToString:@"playlist"] || [[item identifier] isEqualToString:@"medialibrary"] )
{
NSPasteboard *o_pasteboard = [info draggingPasteboard];
if ([[o_pasteboard types] containsObject: @"VLCPlaylistItemPboardType"] || [[o_pasteboard types] containsObject: NSFilenamesPboardType])
return NSDragOperationGeneric;
}
return NSDragOperationNone;
}
- (BOOL)sourceList:(PXSourceList *)aSourceList acceptDrop:(id <NSDraggingInfo>)info item:(id)item childIndex:(NSInteger)index
{
NSPasteboard *o_pasteboard = [info draggingPasteboard];
playlist_t * p_playlist = pl_Get( VLCIntf );
playlist_item_t *p_node;
if ([[item identifier] isEqualToString:@"playlist"])
p_node = p_playlist->p_local_category;
else
p_node = p_playlist->p_ml_category;
if( [[o_pasteboard types] containsObject: NSFilenamesPboardType] )
{
NSArray *o_values = [[o_pasteboard propertyListForType: NSFilenamesPboardType] sortedArrayUsingSelector: @selector(caseInsensitiveCompare:)];
NSUInteger count = [o_values count];
NSMutableArray *o_array = [NSMutableArray arrayWithCapacity:count];
for( NSUInteger i = 0; i < count; i++)
{
NSDictionary *o_dic;
char *psz_uri = make_URI([[o_values objectAtIndex:i] UTF8String], NULL);
if( !psz_uri )
continue;
o_dic = [NSDictionary dictionaryWithObject:[NSString stringWithCString:psz_uri encoding:NSUTF8StringEncoding] forKey:@"ITEM_URL"];
free( psz_uri );
[o_array addObject: o_dic];
}
[[[VLCMain sharedInstance] playlist] appendNodeArray:o_array inNode: p_node atPos:-1 enqueue:YES];
return YES;
}
else if( [[o_pasteboard types] containsObject: @"VLCPlaylistItemPboardType"] )
{
NSArray * array = [[[VLCMain sharedInstance] playlist] draggedItems];
NSUInteger count = [array count];
playlist_item_t * p_item = NULL;
PL_LOCK;
for( NSUInteger i = 0; i < count; i++ )
{
p_item = [[array objectAtIndex:i] pointerValue];
if( !p_item ) continue;
playlist_NodeAddCopy( p_playlist, p_item, p_node, PLAYLIST_END );
}
PL_UNLOCK;
return YES;
}
return NO;
}
- (id)sourceList:(PXSourceList *)aSourceList persistentObjectForItem:(id)item
{
return [item identifier];
}
- (id)sourceList:(PXSourceList *)aSourceList itemForPersistentObject:(id)object
{
/* the following code assumes for sakes of simplicity that only the top level
* items are allowed to have children */
NSArray * array = [NSArray arrayWithArray: o_sidebaritems]; // read-only arrays are noticebly faster
NSUInteger count = [array count];
if (count < 1)
return nil;
for (NSUInteger x = 0; x < count; x++)
{
id item = [array objectAtIndex: x]; // save one objc selector call
if ([[item identifier] isEqualToString:object])
return item;
}
return nil;
}
@end
@implementation VLCDetachedVideoWindow
- (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)styleMask
backing:(NSBackingStoreType)backingType defer:(BOOL)flag
{
b_dark_interface = config_GetInt( VLCIntf, "macosx-interfacestyle" );
if (b_dark_interface)
{
#ifdef MAC_OS_X_VERSION_10_7
if (OSX_LION)
styleMask = NSBorderlessWindowMask | NSResizableWindowMask;
else
styleMask = NSBorderlessWindowMask;
#else
styleMask = NSBorderlessWindowMask;
#endif
}
self = [super initWithContentRect:contentRect styleMask:styleMask
backing:backingType defer:flag];
/* we want to be moveable regardless of our style */
[self setMovableByWindowBackground: YES];
/* we don't want this window to be restored on relaunch */
if (OSX_LION)
[self setRestorable:NO];
return self;
}
- (void)awakeFromNib
{
if (b_dark_interface)
{
[self setBackgroundColor: [NSColor clearColor]];
[self setOpaque: NO];
[self display];
[self setHasShadow:NO];
[self setHasShadow:YES];
}
}
- (IBAction)fullscreen:(id)sender
{
[[VLCCoreInteraction sharedInstance] toggleFullscreen];
}
- (void)updateFullscreen
{
[[VLCMain sharedInstance] fullscreenChanged];
}
- (BOOL)isFullscreen
{
return [[VLCMainWindow sharedInstance] isFullscreen];
}
- (void)performClose:(id)sender
{
if (b_dark_interface)
[[VLCMainWindow sharedInstance] performClose: sender];
else
[super performClose: sender];
}
- (void)performMiniaturize:(id)sender
{
if (b_dark_interface)
[self miniaturize: sender];
else
[super performMiniaturize: sender];
}
- (void)performZoom:(id)sender
{
if (b_dark_interface)
[self customZoom: sender];
else
[super performZoom: sender];
}
- (void)zoom:(id)sender
{
if (b_dark_interface)
[self customZoom: sender];
else
[super zoom: sender];
}
- (BOOL)canBecomeKeyWindow
{
return YES;
}
- (BOOL)validateMenuItem:(NSMenuItem *)menuItem
{
SEL s_menuAction = [menuItem action];
if ((s_menuAction == @selector(performClose:)) || (s_menuAction == @selector(performMiniaturize:)) || (s_menuAction == @selector(performZoom:)))
return YES;
return [super validateMenuItem:menuItem];
}
/**
* Given a proposed frame rectangle, return a modified version
* which will fit inside the screen.
*
* This method is based upon NSWindow.m, part of the GNUstep GUI Library, licensed under LGPLv2+.
* Authors: Scott Christley <scottc@net-community.com>, Venkat Ajjanagadde <venkat@ocbi.com>,
* Felipe A. Rodriguez <far@ix.netcom.com>, Richard Frith-Macdonald <richard@brainstorm.co.uk>
* Copyright (C) 1996 Free Software Foundation, Inc.
*/
- (NSRect) customConstrainFrameRect: (NSRect)frameRect toScreen: (NSScreen*)screen
{
NSRect screenRect = [screen visibleFrame];
float difference;
/* Move top edge of the window inside the screen */
difference = NSMaxY (frameRect) - NSMaxY (screenRect);
if (difference > 0)
{
frameRect.origin.y -= difference;
}
/* If the window is resizable, resize it (if needed) so that the
bottom edge is on the screen or can be on the screen when the user moves
the window */
difference = NSMaxY (screenRect) - NSMaxY (frameRect);
if (_styleMask & NSResizableWindowMask)
{
float difference2;
difference2 = screenRect.origin.y - frameRect.origin.y;
difference2 -= difference;
// Take in account the space between the top of window and the top of the
// screen which can be used to move the bottom of the window on the screen
if (difference2 > 0)
{
frameRect.size.height -= difference2;
frameRect.origin.y += difference2;
}
/* Ensure that resizing doesn't makewindow smaller than minimum */
difference2 = [self minSize].height - frameRect.size.height;
if (difference2 > 0)
{
frameRect.size.height += difference2;
frameRect.origin.y -= difference2;
}
}
return frameRect;
}
#define DIST 3
/**
Zooms the receiver. This method calls the delegate method
windowShouldZoom:toFrame: to determine if the window should
be allowed to zoom to full screen.
*
* This method is based upon NSWindow.m, part of the GNUstep GUI Library, licensed under LGPLv2+.
* Authors: Scott Christley <scottc@net-community.com>, Venkat Ajjanagadde <venkat@ocbi.com>,
* Felipe A. Rodriguez <far@ix.netcom.com>, Richard Frith-Macdonald <richard@brainstorm.co.uk>
* Copyright (C) 1996 Free Software Foundation, Inc.
*/
- (void) customZoom: (id)sender
{
NSRect maxRect = [[self screen] visibleFrame];
NSRect currentFrame = [self frame];
if ([[self delegate] respondsToSelector: @selector(windowWillUseStandardFrame:defaultFrame:)])
{
maxRect = [[self delegate] windowWillUseStandardFrame: self defaultFrame: maxRect];
}
maxRect = [self customConstrainFrameRect: maxRect toScreen: [self screen]];
// Compare the new frame with the current one
if ((abs(NSMaxX(maxRect) - NSMaxX(currentFrame)) < DIST)
&& (abs(NSMaxY(maxRect) - NSMaxY(currentFrame)) < DIST)
&& (abs(NSMinX(maxRect) - NSMinX(currentFrame)) < DIST)
&& (abs(NSMinY(maxRect) - NSMinY(currentFrame)) < DIST))
{
// Already in zoomed mode, reset user frame, if stored
if ([self frameAutosaveName] != nil)
{
[self setFrame: previousSavedFrame display: YES animate: YES];
[self saveFrameUsingName: [self frameAutosaveName]];
}
return;
}
if ([self frameAutosaveName] != nil)
{
[self saveFrameUsingName: [self frameAutosaveName]];
previousSavedFrame = [self frame];
}
[self setFrame: maxRect display: YES animate: YES];
}
@end