]> git.sesse.net Git - vlc/blob - modules/gui/macosx/MainWindow.m
ea804c267125a0dfbac62001695fe9c9282f69cd
[vlc] / modules / gui / macosx / MainWindow.m
1 /*****************************************************************************
2  * MainWindow.m: MacOS X interface module
3  *****************************************************************************
4  * Copyright (C) 2002-2012 VLC authors and VideoLAN
5  * $Id$
6  *
7  * Authors: Felix Paul Kühne <fkuehne -at- videolan -dot- org>
8  *          Jon Lech Johansen <jon-vl@nanocrew.net>
9  *          Christophe Massiot <massiot@via.ecp.fr>
10  *          Derk-Jan Hartman <hartman at videolan.org>
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or
15  * (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
25  *****************************************************************************/
26
27 #import "CompatibilityFixes.h"
28 #import "MainWindow.h"
29 #import "intf.h"
30 #import "CoreInteraction.h"
31 #import "AudioEffects.h"
32 #import "MainMenu.h"
33 #import "open.h"
34 #import "controls.h" // TODO: remove me
35 #import "SideBarItem.h"
36 #import <vlc_playlist.h>
37 #import <vlc_aout_intf.h>
38 #import <vlc_url.h>
39 #import <vlc_strings.h>
40 #import <vlc_services_discovery.h>
41 #import <vlc_aout_intf.h>
42
43 @implementation VLCMainWindow
44 static VLCMainWindow *_o_sharedInstance = nil;
45
46 + (VLCMainWindow *)sharedInstance
47 {
48     return _o_sharedInstance ? _o_sharedInstance : [[self alloc] init];
49 }
50
51 #pragma mark -
52 #pragma mark Initialization
53
54 - (id)init
55 {
56     if( _o_sharedInstance)
57     {
58         [self dealloc];
59         return _o_sharedInstance;
60     }
61     else
62     {
63         o_fspanel = [[VLCFSPanel alloc] init];
64         _o_sharedInstance = [super init];
65     }
66
67     return _o_sharedInstance;
68 }
69
70 - (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)styleMask
71                   backing:(NSBackingStoreType)backingType defer:(BOOL)flag
72 {
73     b_dark_interface = config_GetInt( VLCIntf, "macosx-interfacestyle" );
74
75     if (b_dark_interface)
76     {
77 #ifdef MAC_OS_X_VERSION_10_7
78         styleMask = NSBorderlessWindowMask | NSResizableWindowMask;
79 #else
80         styleMask = NSBorderlessWindowMask;
81 #endif
82     }
83
84     self = [super initWithContentRect:contentRect styleMask:styleMask
85                               backing:backingType defer:flag];
86
87     [[VLCMain sharedInstance] updateTogglePlaylistState];
88
89     /* we want to be moveable regardless of our style */
90     [self setMovableByWindowBackground: YES];
91
92     /* we don't want this window to be restored on relaunch */
93     if (OSX_LION)
94         [self setRestorable:NO];
95
96     return self;
97 }
98
99 - (BOOL)performKeyEquivalent:(NSEvent *)o_event
100 {
101     /* We indeed want to prioritize Cocoa key equivalent against libvlc,
102      so we perform the menu equivalent now. */
103     if([[NSApp mainMenu] performKeyEquivalent:o_event])
104         return TRUE;
105
106     return [[VLCMain sharedInstance] hasDefinedShortcutKey:o_event] || [(VLCControls *)[[VLCMain sharedInstance] controls] keyEvent:o_event];
107 }
108
109 - (void)dealloc
110 {
111     if (b_dark_interface)
112         [o_color_backdrop release];
113
114     [[NSNotificationCenter defaultCenter] removeObserver: self];
115     config_PutInt( VLCIntf->p_libvlc, "volume", i_lastShownVolume );
116     [self saveFrameUsingName: [self frameAutosaveName]];
117     [o_sidebaritems release];
118     [super dealloc];
119 }
120
121 - (void)awakeFromNib
122 {
123     /* setup the styled interface */
124 #ifdef MAC_OS_X_VERSION_10_7
125     b_nativeFullscreenMode = config_GetInt( VLCIntf, "macosx-nativefullscreenmode" );
126 #else
127     b_nativeFullscreenMode = NO;
128 #endif
129     i_lastShownVolume = -1;
130     t_hide_mouse_timer = nil;
131
132     [o_play_btn setToolTip: _NS("Play/Pause")];
133     [o_bwd_btn setToolTip: _NS("Backward")];
134     [o_fwd_btn setToolTip: _NS("Forward")];
135     [o_stop_btn setToolTip: _NS("Stop")];
136     [o_playlist_btn setToolTip: _NS("Show/Hide Playlist")];
137     [o_repeat_btn setToolTip: _NS("Repeat")];
138     [o_shuffle_btn setToolTip: _NS("Shuffle")];
139     [o_effects_btn setToolTip: _NS("Effects")];
140     [o_fullscreen_btn setToolTip: _NS("Toggle Fullscreen mode")];
141     [[o_search_fld cell] setPlaceholderString: _NS("Search")];
142     [o_volume_sld setToolTip: _NS("Volume")];
143     [o_volume_down_btn setToolTip: _NS("Mute")];
144     [o_volume_up_btn setToolTip: _NS("Full Volume")];
145     [o_time_sld setToolTip: _NS("Position")];
146     [o_dropzone_btn setTitle: _NS("Open media...")];
147     [o_dropzone_lbl setStringValue: _NS("Drop media here")];
148
149     if (!b_dark_interface) {
150         [o_bottombar_view setImage: [NSImage imageNamed:@"bottom-background"]];
151         [o_bwd_btn setImage: [NSImage imageNamed:@"back"]];
152         [o_bwd_btn setAlternateImage: [NSImage imageNamed:@"back-pressed"]];
153         o_play_img = [[NSImage imageNamed:@"play"] retain];
154         o_play_pressed_img = [[NSImage imageNamed:@"play-pressed"] retain];
155         o_pause_img = [[NSImage imageNamed:@"pause"] retain];
156         o_pause_pressed_img = [[NSImage imageNamed:@"pause-pressed"] retain];
157         [o_fwd_btn setImage: [NSImage imageNamed:@"forward"]];
158         [o_fwd_btn setAlternateImage: [NSImage imageNamed:@"forward-pressed"]];
159         [o_stop_btn setImage: [NSImage imageNamed:@"stop"]];
160         [o_stop_btn setAlternateImage: [NSImage imageNamed:@"stop-pressed"]];
161         [o_playlist_btn setImage: [NSImage imageNamed:@"playlist"]];
162         [o_playlist_btn setAlternateImage: [NSImage imageNamed:@"playlist-pressed"]];
163         o_repeat_img = [[NSImage imageNamed:@"repeat"] retain];
164         o_repeat_pressed_img = [[NSImage imageNamed:@"repeat-pressed"] retain];
165         o_repeat_all_img  = [[NSImage imageNamed:@"repeat-all"] retain];
166         o_repeat_all_pressed_img = [[NSImage imageNamed:@"repeat-all-pressed"] retain];
167         o_repeat_one_img = [[NSImage imageNamed:@"repeat-one"] retain];
168         o_repeat_one_pressed_img = [[NSImage imageNamed:@"repeat-one-pressed"] retain];
169         o_shuffle_img = [[NSImage imageNamed:@"shuffle"] retain];
170         o_shuffle_pressed_img = [[NSImage imageNamed:@"shuffle-pressed"] retain];
171         o_shuffle_on_img = [[NSImage imageNamed:@"shuffle-blue"] retain];
172         o_shuffle_on_pressed_img = [[NSImage imageNamed:@"shuffle-blue-pressed"] retain];
173         [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"]];
174         [o_volume_down_btn setImage: [NSImage imageNamed:@"volume-low"]];
175         [o_volume_track_view setImage: [NSImage imageNamed:@"volume-slider-track"]];
176         [o_volume_up_btn setImage: [NSImage imageNamed:@"volume-high"]];
177         if (OSX_LION && b_nativeFullscreenMode)
178         {
179             [o_effects_btn setImage: [NSImage imageNamed:@"effects-one-button"]];
180             [o_effects_btn setAlternateImage: [NSImage imageNamed:@"effects-one-button-blue"]];
181         }
182         else
183         {
184             [o_effects_btn setImage: [NSImage imageNamed:@"effects-double-buttons"]];
185             [o_effects_btn setAlternateImage: [NSImage imageNamed:@"effects-double-buttons-pressed"]];
186         }
187         [o_fullscreen_btn setImage: [NSImage imageNamed:@"fullscreen-double-buttons"]];
188         [o_fullscreen_btn setAlternateImage: [NSImage imageNamed:@"fullscreen-double-buttons-pressed"]];
189         [o_time_sld_fancygradient_view setImagesLeft:[NSImage imageNamed:@"progression-fill-left"] middle:[NSImage imageNamed:@"progression-fill-middle"] right:[NSImage imageNamed:@"progression-fill-right"]];
190     }
191     else
192     {
193         [o_bottombar_view setImage: [NSImage imageNamed:@"bottom-background_dark"]];
194         [o_bwd_btn setImage: [NSImage imageNamed:@"back_dark"]];
195         [o_bwd_btn setAlternateImage: [NSImage imageNamed:@"back-pressed_dark"]];
196         o_play_img = [[NSImage imageNamed:@"play_dark"] retain];
197         o_play_pressed_img = [[NSImage imageNamed:@"play-pressed_dark"] retain];
198         o_pause_img = [[NSImage imageNamed:@"pause_dark"] retain];
199         o_pause_pressed_img = [[NSImage imageNamed:@"pause-pressed_dark"] retain];
200         [o_fwd_btn setImage: [NSImage imageNamed:@"forward_dark"]];
201         [o_fwd_btn setAlternateImage: [NSImage imageNamed:@"forward-pressed_dark"]];
202         [o_stop_btn setImage: [NSImage imageNamed:@"stop_dark"]];
203         [o_stop_btn setAlternateImage: [NSImage imageNamed:@"stop-pressed_dark"]];
204         [o_playlist_btn setImage: [NSImage imageNamed:@"playlist_dark"]];
205         [o_playlist_btn setAlternateImage: [NSImage imageNamed:@"playlist-pressed_dark"]];
206         o_repeat_img = [[NSImage imageNamed:@"repeat_dark"] retain];
207         o_repeat_pressed_img = [[NSImage imageNamed:@"repeat-pressed_dark"] retain];
208         o_repeat_all_img  = [[NSImage imageNamed:@"repeat-all-blue_dark"] retain];
209         o_repeat_all_pressed_img = [[NSImage imageNamed:@"repeat-all-blue-pressed_dark"] retain];
210         o_repeat_one_img = [[NSImage imageNamed:@"repeat-one-blue_dark"] retain];
211         o_repeat_one_pressed_img = [[NSImage imageNamed:@"repeat-one-blue-pressed_dark"] retain];
212         o_shuffle_img = [[NSImage imageNamed:@"shuffle_dark"] retain];
213         o_shuffle_pressed_img = [[NSImage imageNamed:@"shuffle-pressed_dark"] retain];
214         o_shuffle_on_img = [[NSImage imageNamed:@"shuffle-blue_dark"] retain];
215         o_shuffle_on_pressed_img = [[NSImage imageNamed:@"shuffle-blue-pressed_dark"] retain];
216         [o_time_fld setTextColor: [NSColor colorWithCalibratedRed:229.0 green:229.0 blue:229.0 alpha:100.0]];
217         [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"]];
218         [o_volume_down_btn setImage: [NSImage imageNamed:@"volume-low_dark"]];
219         [o_volume_track_view setImage: [NSImage imageNamed:@"volume-slider-track_dark"]];
220         [o_volume_up_btn setImage: [NSImage imageNamed:@"volume-high_dark"]];
221         if (OSX_LION && b_nativeFullscreenMode)
222         {
223             [o_effects_btn setImage: [NSImage imageNamed:@"effects-one-button_dark"]];
224             [o_effects_btn setAlternateImage: [NSImage imageNamed:@"effects-one-button-blue_dark"]];
225         }
226         else
227         {
228             [o_effects_btn setImage: [NSImage imageNamed:@"effects-double-buttons_dark"]];
229             [o_effects_btn setAlternateImage: [NSImage imageNamed:@"effects-double-buttons-pressed_dark"]];            
230         }
231         [o_fullscreen_btn setImage: [NSImage imageNamed:@"fullscreen-double-buttons_dark"]];
232         [o_fullscreen_btn setAlternateImage: [NSImage imageNamed:@"fullscreen-double-buttons-pressed_dark"]];
233         [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"]];
234     }
235     [o_repeat_btn setImage: o_repeat_img];
236     [o_repeat_btn setAlternateImage: o_repeat_pressed_img];
237     [o_shuffle_btn setImage: o_shuffle_img];
238     [o_shuffle_btn setAlternateImage: o_shuffle_pressed_img];
239     [o_play_btn setImage: o_play_img];
240     [o_play_btn setAlternateImage: o_play_pressed_img];
241     BOOL b_mute = ![[VLCCoreInteraction sharedInstance] isMuted];
242     [o_volume_sld setEnabled: b_mute];
243     [o_volume_up_btn setEnabled: b_mute];
244
245     /* interface builder action */
246     [self setDelegate: self];
247     [self setExcludedFromWindowsMenu: YES];
248     [self setAcceptsMouseMovedEvents: YES];
249     // Set that here as IB seems to be buggy
250     if (b_dark_interface)
251         [self setContentMinSize:NSMakeSize(500., (288. + [o_titlebar_view frame].size.height))];
252     else
253         [self setContentMinSize:NSMakeSize(500., 288.)];
254     [self setTitle: _NS("VLC media player")];
255     [o_playlist_btn setEnabled:NO];
256     o_temp_view = [[NSView alloc] init];
257     [o_temp_view setAutoresizingMask:NSViewHeightSizable | NSViewWidthSizable];
258     [o_dropzone_view setFrame: [o_playlist_table frame]];
259     [o_left_split_view setFrame: [o_sidebar_view frame]];
260     if (OSX_LION && b_nativeFullscreenMode)
261     {
262         [self setCollectionBehavior: NSWindowCollectionBehaviorFullScreenPrimary];
263         NSRect frame;
264         float f_width = [o_fullscreen_btn frame].size.width;
265
266         #define moveItem( item ) \
267         frame = [item frame]; \
268         frame.origin.x = f_width + frame.origin.x; \
269         [item setFrame: frame]
270
271         moveItem( o_effects_btn );
272         moveItem( o_volume_up_btn );
273         moveItem( o_volume_sld );
274         moveItem( o_volume_track_view );
275         moveItem( o_volume_down_btn );
276         moveItem( o_time_fld );
277         #undef moveItem
278
279         #define enlargeItem( item ) \
280         frame = [item frame]; \
281         frame.size.width = f_width + frame.size.width; \
282         [item setFrame: frame]
283
284         enlargeItem( o_time_sld );
285         enlargeItem( o_progress_bar );
286         enlargeItem( o_time_sld_background );
287         enlargeItem( o_time_sld_fancygradient_view );
288         #undef enlargeItem
289
290         [o_fullscreen_btn removeFromSuperviewWithoutNeedingDisplay];
291     }
292     else
293         [o_titlebar_view setFullscreenButtonHidden: YES];
294
295     if (OSX_LION)
296     {
297         /* the default small size of the search field is slightly different on Lion, let's work-around that */
298         NSRect frame;
299         frame = [o_search_fld frame];
300         frame.origin.y = frame.origin.y + 2.0;
301         frame.size.height = frame.size.height - 1.0;
302         [o_search_fld setFrame: frame];
303     }
304
305     /* create the sidebar */
306     o_sidebaritems = [[NSMutableArray alloc] init];
307     SideBarItem *libraryItem = [SideBarItem itemWithTitle:_NS("LIBRARY") identifier:@"library"];
308     SideBarItem *playlistItem = [SideBarItem itemWithTitle:_NS("Playlist") identifier:@"playlist"];
309     [playlistItem setIcon: [NSImage imageNamed:@"sidebar-playlist"]];
310     SideBarItem *mycompItem = [SideBarItem itemWithTitle:_NS("MY COMPUTER") identifier:@"mycomputer"];
311     SideBarItem *devicesItem = [SideBarItem itemWithTitle:_NS("DEVICES") identifier:@"devices"];
312     SideBarItem *lanItem = [SideBarItem itemWithTitle:_NS("LOCAL NETWORK") identifier:@"localnetwork"];
313     SideBarItem *internetItem = [SideBarItem itemWithTitle:_NS("INTERNET") identifier:@"internet"];
314
315     /* SD subnodes, inspired by the Qt4 intf */
316     char **ppsz_longnames;
317     int *p_categories;
318     char **ppsz_names = vlc_sd_GetNames( pl_Get( VLCIntf ), &ppsz_longnames, &p_categories );
319     if (!ppsz_names)
320         msg_Err( VLCIntf, "no sd item found" ); //TODO
321     char **ppsz_name = ppsz_names, **ppsz_longname = ppsz_longnames;
322     int *p_category = p_categories;
323     NSMutableArray *internetItems = [[NSMutableArray alloc] init];
324     NSMutableArray *devicesItems = [[NSMutableArray alloc] init];
325     NSMutableArray *lanItems = [[NSMutableArray alloc] init];
326     NSMutableArray *mycompItems = [[NSMutableArray alloc] init];
327     NSString *o_identifier;
328     for (; *ppsz_name; ppsz_name++, ppsz_longname++, p_category++)
329     {
330         o_identifier = [NSString stringWithCString: *ppsz_name encoding: NSUTF8StringEncoding];
331         o_identifier = [[o_identifier componentsSeparatedByString:@"{"] objectAtIndex:0];
332         switch (*p_category) {
333             case SD_CAT_INTERNET:
334                 {
335                     [internetItems addObject: [SideBarItem itemWithTitle: [NSString stringWithCString: *ppsz_longname encoding: NSUTF8StringEncoding] identifier: o_identifier]];
336                     if (!strncmp( *ppsz_name, "podcast", 7 ))
337                         [[internetItems lastObject] setIcon: [NSImage imageNamed:@"sidebar-podcast"]];
338                     else
339                         [[internetItems lastObject] setIcon: [NSImage imageNamed:@"NSApplicationIcon"]];
340                 }
341                 break;
342             case SD_CAT_DEVICES:
343                 {
344                     [devicesItems addObject: [SideBarItem itemWithTitle: [NSString stringWithCString: *ppsz_longname encoding: NSUTF8StringEncoding] identifier: o_identifier]];
345                     [[devicesItems lastObject] setIcon: [NSImage imageNamed:@"NSApplicationIcon"]];
346                 }
347                 break;
348             case SD_CAT_LAN:
349                 {
350                     [lanItems addObject: [SideBarItem itemWithTitle: [NSString stringWithCString: *ppsz_longname encoding: NSUTF8StringEncoding] identifier: o_identifier]];
351                     [[lanItems lastObject] setIcon: [NSImage imageNamed:@"sidebar-local"]];
352                 }
353                 break;
354             case SD_CAT_MYCOMPUTER:
355                 {
356                     [mycompItems addObject: [SideBarItem itemWithTitle: [NSString stringWithCString: *ppsz_longname encoding: NSUTF8StringEncoding] identifier: o_identifier]];
357                     if (!strncmp( *ppsz_name, "video_dir", 9 ))
358                         [[mycompItems lastObject] setIcon: [NSImage imageNamed:@"sidebar-movie"]];
359                     else if (!strncmp( *ppsz_name, "audio_dir", 9 ))
360                         [[mycompItems lastObject] setIcon: [NSImage imageNamed:@"sidebar-music"]];
361                     else if (!strncmp( *ppsz_name, "picture_dir", 11 ))
362                         [[mycompItems lastObject] setIcon: [NSImage imageNamed:@"sidebar-pictures"]];
363                     else
364                         [[mycompItems lastObject] setIcon: [NSImage imageNamed:@"NSApplicationIcon"]];
365                 }
366                 break;
367             default:
368                 msg_Warn( VLCIntf, "unknown SD type found, skipping (%s)", *ppsz_name );
369                 break;
370         }
371
372         free( *ppsz_name );
373         free( *ppsz_longname );
374     }
375     [mycompItem setChildren: [NSArray arrayWithArray: mycompItems]];
376     [devicesItem setChildren: [NSArray arrayWithArray: devicesItems]];
377     [lanItem setChildren: [NSArray arrayWithArray: lanItems]];
378     [internetItem setChildren: [NSArray arrayWithArray: internetItems]];
379     [mycompItems release];
380     [devicesItems release];
381     [lanItems release];
382     [internetItems release];
383     free( ppsz_names );
384     free( ppsz_longnames );
385     free( p_categories );
386
387     [libraryItem setChildren: [NSArray arrayWithObject: playlistItem]];
388     [o_sidebaritems addObject: libraryItem];
389     if ([mycompItem hasChildren])
390         [o_sidebaritems addObject: mycompItem];
391     if ([devicesItem hasChildren])
392         [o_sidebaritems addObject: devicesItem];
393     if ([lanItem hasChildren])
394         [o_sidebaritems addObject: lanItem];
395     if ([internetItem hasChildren])
396         [o_sidebaritems addObject: internetItem];
397
398     [o_sidebar_view reloadData];
399     [o_sidebar_view selectRowIndexes:[NSIndexSet indexSetWithIndex:0] byExtendingSelection:YES];
400     NSUInteger i_sidebaritem_count = [o_sidebaritems count];
401     for (NSUInteger x = 0; x < i_sidebaritem_count; x++)
402         [o_sidebar_view expandItem: [o_sidebaritems objectAtIndex: x] expandChildren: YES];
403
404     if( b_dark_interface )
405     {
406         [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(windowResizedOrMoved:) name: NSWindowDidResizeNotification object: nil];
407         [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(windowResizedOrMoved:) name: NSWindowDidMoveNotification object: nil];
408
409         [self setBackgroundColor: [NSColor clearColor]];
410         [self setOpaque: NO];
411         [self setHasShadow:YES];
412
413         NSRect winrect;
414         CGFloat f_titleBarHeight = [o_titlebar_view frame].size.height;
415         winrect = [self frame];
416
417         [o_titlebar_view setFrame: NSMakeRect( 0, winrect.size.height - f_titleBarHeight,
418                                               winrect.size.width, f_titleBarHeight )];
419         [[self contentView] addSubview: o_titlebar_view];
420
421         winrect.size.height = winrect.size.height + f_titleBarHeight;
422         [self setFrame: winrect display:NO animate:NO];
423         winrect = [o_split_view frame];
424         winrect.size.height = winrect.size.height - f_titleBarHeight;
425         [o_split_view setFrame: winrect];
426         [o_video_view setFrame: winrect];
427         previousSavedFrame = winrect;
428
429         o_color_backdrop = [[VLCColorView alloc] initWithFrame: [o_split_view frame]];
430         [[self contentView] addSubview: o_color_backdrop positioned: NSWindowBelow relativeTo: o_split_view];
431         [o_color_backdrop setAutoresizingMask:NSViewHeightSizable | NSViewWidthSizable];
432
433         [self display];
434     }
435     else
436     {
437         NSRect frame;
438         frame = [o_time_sld_fancygradient_view frame];
439         frame.size.height = frame.size.height - 1;
440         frame.origin.y = frame.origin.y + 1;
441         [o_time_sld_fancygradient_view setFrame: frame];
442
443         [o_video_view setFrame: [o_split_view frame]];
444         [o_playlist_table setBorderType: NSNoBorder];
445         [o_sidebar_scrollview setBorderType: NSNoBorder];
446     }
447
448     if (OSX_LION)
449         [o_resize_view setImage: NULL];
450
451     if ([self styleMask] & NSResizableWindowMask)
452         [o_resize_view removeFromSuperviewWithoutNeedingDisplay];
453
454     if (OSX_LEOPARD)
455         [o_time_sld_fancygradient_view removeFromSuperviewWithoutNeedingDisplay];
456
457     [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(someWindowWillClose:) name: NSWindowWillCloseNotification object: nil];
458     [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(someWindowWillMiniaturize:) name: NSWindowWillMiniaturizeNotification object:nil];
459 }
460
461 #pragma mark -
462 #pragma mark Button Actions
463
464 - (IBAction)play:(id)sender
465 {
466     [[VLCCoreInteraction sharedInstance] play];
467 }
468
469 - (void)resetPreviousButton
470 {
471     if (([NSDate timeIntervalSinceReferenceDate] - last_bwd_event) >= 0.35) {
472         // seems like no further event occured, so let's switch the playback item
473         [[VLCCoreInteraction sharedInstance] previous];
474         just_triggered_previous = NO;
475     }
476 }
477
478 - (void)resetBackwardSkip
479 {
480     // the user stopped skipping, so let's allow him to change the item
481     if (([NSDate timeIntervalSinceReferenceDate] - last_bwd_event) >= 0.35)
482         just_triggered_previous = NO;
483 }
484
485 - (IBAction)bwd:(id)sender
486 {
487     if(!just_triggered_previous)
488     {
489         just_triggered_previous = YES;
490         [self performSelector:@selector(resetPreviousButton)
491                    withObject: NULL
492                    afterDelay:0.40];
493     }
494     else
495     {
496         if (([NSDate timeIntervalSinceReferenceDate] - last_fwd_event) > 0.12 )
497         {
498             // we just skipped 3 "continous" events, otherwise we are too fast
499             [[VLCCoreInteraction sharedInstance] backward];
500             last_bwd_event = [NSDate timeIntervalSinceReferenceDate];
501             [self performSelector:@selector(resetBackwardSkip)
502                        withObject: NULL
503                        afterDelay:0.40];
504         }
505     }
506 }
507
508 - (void)resetNextButton
509 {
510     if (([NSDate timeIntervalSinceReferenceDate] - last_fwd_event) >= 0.35) {
511         // seems like no further event occured, so let's switch the playback item
512         [[VLCCoreInteraction sharedInstance] next];
513         just_triggered_next = NO;
514     }
515 }
516
517 - (void)resetForwardSkip
518 {
519     // the user stopped skipping, so let's allow him to change the item
520     if (([NSDate timeIntervalSinceReferenceDate] - last_fwd_event) >= 0.35)
521         just_triggered_next = NO;
522 }
523
524 - (IBAction)fwd:(id)sender
525 {
526    if(!just_triggered_next)
527     {
528         just_triggered_next = YES;
529         [self performSelector:@selector(resetNextButton)
530                    withObject: NULL
531                    afterDelay:0.40];
532     }
533     else
534     {
535         if (([NSDate timeIntervalSinceReferenceDate] - last_fwd_event) > 0.12 )
536         {
537             // we just skipped 3 "continous" events, otherwise we are too fast
538             [[VLCCoreInteraction sharedInstance] forward];
539             last_fwd_event = [NSDate timeIntervalSinceReferenceDate];
540             [self performSelector:@selector(resetForwardSkip)
541                        withObject: NULL
542                        afterDelay:0.40];
543         }
544     }
545 }
546
547 - (IBAction)stop:(id)sender
548 {
549     [[VLCCoreInteraction sharedInstance] stop];
550 }
551
552 - (IBAction)togglePlaylist:(id)sender
553 {
554     if (!b_nonembedded)
555     {
556         if ([o_video_view isHidden] && [o_playlist_btn isEnabled]) {
557             [o_split_view setHidden: YES];
558             [o_video_view setHidden: NO];
559         }
560         else
561         {
562             [o_video_view setHidden: YES];
563             [o_split_view setHidden: NO];
564         }
565     }
566     else
567     {
568         [o_split_view setHidden: NO];
569         [o_playlist_table setHidden: NO];
570         [o_video_view setHidden: ![[VLCMain sharedInstance] activeVideoPlayback]];
571     }
572 }
573
574 - (void)setRepeatOne
575 {
576     [o_repeat_btn setImage: o_repeat_one_img];
577     [o_repeat_btn setAlternateImage: o_repeat_one_pressed_img];   
578 }
579
580 - (void)setRepeatAll
581 {
582     [o_repeat_btn setImage: o_repeat_all_img];
583     [o_repeat_btn setAlternateImage: o_repeat_all_pressed_img];
584 }
585
586 - (void)setRepeatOff
587 {
588     [o_repeat_btn setImage: o_repeat_img];
589     [o_repeat_btn setAlternateImage: o_repeat_pressed_img];
590 }
591
592 - (IBAction)repeat:(id)sender
593 {
594     vlc_value_t looping,repeating;
595     intf_thread_t * p_intf = VLCIntf;
596     playlist_t * p_playlist = pl_Get( p_intf );
597
598     var_Get( p_playlist, "repeat", &repeating );
599     var_Get( p_playlist, "loop", &looping );
600
601     if( !repeating.b_bool && !looping.b_bool )
602     {
603         /* was: no repeating at all, switching to Repeat One */
604         [[VLCCoreInteraction sharedInstance] repeatOne];
605         [self setRepeatOne];
606     }
607     else if( repeating.b_bool && !looping.b_bool )
608     {
609         /* was: Repeat One, switching to Repeat All */
610         [[VLCCoreInteraction sharedInstance] repeatAll];
611         [self setRepeatAll];
612     }
613     else
614     {
615         /* was: Repeat All or bug in VLC, switching to Repeat Off */
616         [[VLCCoreInteraction sharedInstance] repeatOff];
617         [self setRepeatOff];
618     }
619 }
620
621 - (void)setShuffle
622 {
623     bool b_value;
624     playlist_t *p_playlist = pl_Get( VLCIntf );
625     b_value = var_GetBool( p_playlist, "random" );
626         if(b_value) {
627         [o_shuffle_btn setImage: o_shuffle_on_img];
628         [o_shuffle_btn setAlternateImage: o_shuffle_on_pressed_img];
629     }
630     else
631     {
632         [o_shuffle_btn setImage: o_shuffle_img];
633         [o_shuffle_btn setAlternateImage: o_shuffle_pressed_img];
634     }
635 }
636
637 - (IBAction)shuffle:(id)sender
638 {
639     [[VLCCoreInteraction sharedInstance] shuffle];
640     [self setShuffle];
641 }
642
643 - (IBAction)timeSliderAction:(id)sender
644 {
645     float f_updated;
646     input_thread_t * p_input;
647
648     switch( [[NSApp currentEvent] type] )
649     {
650         case NSLeftMouseUp:
651         case NSLeftMouseDown:
652         case NSLeftMouseDragged:
653             f_updated = [sender floatValue];
654             break;
655
656         default:
657             return;
658     }
659     p_input = pl_CurrentInput( VLCIntf );
660     if( p_input != NULL )
661     {
662         vlc_value_t time;
663         vlc_value_t pos;
664         NSString * o_time;
665         char psz_time[MSTRTIME_MAX_SIZE];
666
667         pos.f_float = f_updated / 10000.;
668         var_Set( p_input, "position", pos );
669         [o_time_sld setFloatValue: f_updated];
670
671         var_Get( p_input, "time", &time );
672
673         mtime_t dur = input_item_GetDuration( input_GetItem( p_input ) );
674         if( [o_time_fld timeRemaining] && dur != -1 )
675         {
676             o_time = [NSString stringWithFormat: @"-%s", secstotimestr( psz_time, ((dur - time.i_time) / 1000000) )];
677         }
678         else
679             o_time = [NSString stringWithUTF8String: secstotimestr( psz_time, (time.i_time / 1000000) )];
680
681         [o_time_fld setStringValue: o_time];
682         [o_fspanel setStreamPos: f_updated andTime: o_time];
683         vlc_object_release( p_input );
684     }
685     [self drawFancyGradientEffectForTimeSlider];
686 }
687
688 - (IBAction)volumeAction:(id)sender
689 {
690     if (sender == o_volume_sld)
691         [[VLCCoreInteraction sharedInstance] setVolume: [sender intValue]];
692     else if (sender == o_volume_down_btn)
693     {
694         [[VLCCoreInteraction sharedInstance] mute];
695         [o_volume_sld setIntValue: 0];
696         BOOL b_mute = ![[VLCCoreInteraction sharedInstance] isMuted];
697         [o_volume_sld setEnabled: b_mute];
698         [o_volume_up_btn setEnabled: b_mute];
699     }
700     else
701         [[VLCCoreInteraction sharedInstance] setVolume: AOUT_VOLUME_MAX];
702 }
703
704 - (IBAction)effects:(id)sender
705 {
706     [[VLCMainMenu sharedInstance] showAudioEffects: sender];
707 }
708
709 - (IBAction)fullscreen:(id)sender
710 {
711     [[VLCCoreInteraction sharedInstance] toggleFullscreen];
712 }
713
714 - (IBAction)dropzoneButtonAction:(id)sender
715 {
716     [[[VLCMain sharedInstance] open] openFileGeneric];
717 }
718
719 #pragma mark -
720 #pragma mark overwritten default functionality
721 - (BOOL)canBecomeKeyWindow
722 {
723     return YES;
724 }
725
726 - (BOOL)validateMenuItem:(NSMenuItem *)menuItem
727 {
728         SEL s_menuAction = [menuItem action];
729         if ((s_menuAction == @selector(performClose:)) || (s_menuAction == @selector(performMiniaturize:)) || (s_menuAction == @selector(performZoom:)))
730         return YES;
731
732         return [super validateMenuItem:menuItem];
733 }
734
735 - (BOOL)isMainWindow
736 {
737         return YES;
738 }
739
740 - (void)setTitle:(NSString *)title
741 {
742     if (b_dark_interface)
743         [o_titlebar_view setWindowTitle: title];
744     if (b_nonembedded && [[VLCMain sharedInstance] activeVideoPlayback])
745         [o_nonembedded_window setTitle: title];
746     [super setTitle: title];
747 }
748
749 - (void)performClose:(id)sender
750 {
751     if (b_dark_interface)
752         [self orderOut: sender];
753     else
754         [super performClose: sender];
755 }
756
757 - (void)performMiniaturize:(id)sender
758 {
759     if (b_dark_interface)
760         [self miniaturize: sender];
761     else
762         [super performMiniaturize: sender];
763 }
764
765 - (void)performZoom:(id)sender
766 {
767     if (b_dark_interface)
768         [self customZoom: sender];
769     else
770         [super performZoom: sender];
771 }
772
773 - (void)zoom:(id)sender
774 {
775     if (b_dark_interface)
776         [self customZoom: sender];
777     else
778         [super zoom: sender];
779 }
780
781 /**
782  * Given a proposed frame rectangle, return a modified version
783  * which will fit inside the screen.
784  *
785  * This method is based upon NSWindow.m, part of the GNUstep GUI Library, licensed under LGPLv2+.
786  *    Authors:  Scott Christley <scottc@net-community.com>, Venkat Ajjanagadde <venkat@ocbi.com>,   
787  *              Felipe A. Rodriguez <far@ix.netcom.com>, Richard Frith-Macdonald <richard@brainstorm.co.uk>
788  *    Copyright (C) 1996 Free Software Foundation, Inc.
789  */
790 - (NSRect) customConstrainFrameRect: (NSRect)frameRect toScreen: (NSScreen*)screen
791 {
792     NSRect screenRect = [screen visibleFrame];
793     float difference;
794
795     /* Move top edge of the window inside the screen */
796     difference = NSMaxY (frameRect) - NSMaxY (screenRect);
797     if (difference > 0)
798     {
799         frameRect.origin.y -= difference;
800     }
801
802     /* If the window is resizable, resize it (if needed) so that the
803      bottom edge is on the screen or can be on the screen when the user moves
804      the window */
805     difference = NSMaxY (screenRect) - NSMaxY (frameRect);
806     if (_styleMask & NSResizableWindowMask)
807     {
808         float difference2;
809
810         difference2 = screenRect.origin.y - frameRect.origin.y;
811         difference2 -= difference;
812         // Take in account the space between the top of window and the top of the 
813         // screen which can be used to move the bottom of the window on the screen
814         if (difference2 > 0)
815         {
816             frameRect.size.height -= difference2;
817             frameRect.origin.y += difference2;
818         }
819
820         /* Ensure that resizing doesn't makewindow smaller than minimum */
821         difference2 = [self minSize].height - frameRect.size.height;
822         if (difference2 > 0)
823         {
824             frameRect.size.height += difference2;
825             frameRect.origin.y -= difference2;
826         }
827     }
828
829     return frameRect;
830 }
831
832 #define DIST 3
833
834 /**
835  Zooms the receiver.   This method calls the delegate method
836  windowShouldZoom:toFrame: to determine if the window should
837  be allowed to zoom to full screen.
838  *
839  * This method is based upon NSWindow.m, part of the GNUstep GUI Library, licensed under LGPLv2+.
840  *    Authors:  Scott Christley <scottc@net-community.com>, Venkat Ajjanagadde <venkat@ocbi.com>,   
841  *              Felipe A. Rodriguez <far@ix.netcom.com>, Richard Frith-Macdonald <richard@brainstorm.co.uk>
842  *    Copyright (C) 1996 Free Software Foundation, Inc.
843  */
844 - (void) customZoom: (id)sender
845 {
846     NSRect maxRect = [[self screen] visibleFrame];
847     NSRect currentFrame = [self frame];
848
849     if ([[self delegate] respondsToSelector: @selector(windowWillUseStandardFrame:defaultFrame:)])
850     {
851         maxRect = [[self delegate] windowWillUseStandardFrame: self defaultFrame: maxRect];
852     }
853
854     maxRect = [self customConstrainFrameRect: maxRect toScreen: [self screen]];
855
856     // Compare the new frame with the current one
857     if ((abs(NSMaxX(maxRect) - NSMaxX(currentFrame)) < DIST)
858         && (abs(NSMaxY(maxRect) - NSMaxY(currentFrame)) < DIST)
859         && (abs(NSMinX(maxRect) - NSMinX(currentFrame)) < DIST)
860         && (abs(NSMinY(maxRect) - NSMinY(currentFrame)) < DIST))
861     {
862         // Already in zoomed mode, reset user frame, if stored
863         if ([self frameAutosaveName] != nil)
864         {
865             [self setFrame: previousSavedFrame display: YES animate: YES];
866             [self saveFrameUsingName: [self frameAutosaveName]];
867         }
868         return;
869     }
870
871     if ([self frameAutosaveName] != nil)
872     {
873         [self saveFrameUsingName: [self frameAutosaveName]];
874         previousSavedFrame = [self frame];
875     }
876
877     [self setFrame: maxRect display: YES animate: YES];
878 }
879
880 - (void)windowResizedOrMoved:(NSNotification *)notification
881 {
882     [self saveFrameUsingName: [self frameAutosaveName]];
883 }
884
885 #pragma mark -
886 #pragma mark Update interface and respond to foreign events
887 - (void)showDropZone
888 {
889     [o_right_split_view addSubview: o_dropzone_view];
890     [o_dropzone_view setFrame: [o_playlist_table frame]];
891     [[o_playlist_table animator] setHidden:YES];
892 }
893
894 - (void)hideDropZone
895 {
896     [o_dropzone_view removeFromSuperview];
897     [[o_playlist_table animator] setHidden: NO];
898 }
899
900 - (void)updateTimeSlider
901 {
902     input_thread_t * p_input;
903     p_input = pl_CurrentInput( VLCIntf );
904     if( p_input )
905     {
906         vlc_value_t time;
907         NSString * o_time;
908         vlc_value_t pos;
909         char psz_time[MSTRTIME_MAX_SIZE];
910         float f_updated;
911
912         var_Get( p_input, "position", &pos );
913         f_updated = 10000. * pos.f_float;
914         [o_time_sld setFloatValue: f_updated];
915
916         var_Get( p_input, "time", &time );
917
918         mtime_t dur = input_item_GetDuration( input_GetItem( p_input ) );
919         if( [o_time_fld timeRemaining] && dur != -1 )
920         {
921             o_time = [NSString stringWithFormat: @"-%s", secstotimestr( psz_time, ((dur - time.i_time) / 1000000))];
922         }
923         else
924             o_time = [NSString stringWithUTF8String: secstotimestr( psz_time, (time.i_time / 1000000) )];
925
926         if (dur == -1) {
927             [o_time_sld setEnabled: NO];
928             [o_time_sld setHidden: YES];
929         } else {
930             [o_time_sld setEnabled: YES];
931             [o_time_sld setHidden: NO];
932         }
933
934         [o_time_fld setStringValue: o_time];
935         [o_time_fld setNeedsDisplay:YES];
936         [o_fspanel setStreamPos: f_updated andTime: o_time];
937         vlc_object_release( p_input );
938     }
939     else
940     {
941         [o_time_sld setFloatValue: 0.0];
942         [o_time_fld setStringValue: @"00:00"];
943         [o_time_sld setEnabled: NO];
944         [o_time_sld setHidden: YES];
945     }
946         
947     [self performSelectorOnMainThread:@selector(drawFancyGradientEffectForTimeSlider) withObject:nil waitUntilDone:NO];
948 }
949
950 - (void)updateVolumeSlider
951 {
952     audio_volume_t i_volume;
953     playlist_t * p_playlist = pl_Get( VLCIntf );
954
955     i_volume = aout_VolumeGet( p_playlist );
956
957     if( i_volume != i_lastShownVolume )
958     {
959         [o_volume_sld setIntValue: i_volume];
960         [o_fspanel setVolumeLevel: i_volume];
961     }
962 }
963
964 - (void)updateName
965 {
966     NSAutoreleasePool *o_pool = [[NSAutoreleasePool alloc] init];
967     input_thread_t * p_input;
968     p_input = pl_CurrentInput( VLCIntf );
969     if( p_input )
970     {
971         NSString *aString;
972         char *format = var_InheritString( VLCIntf, "input-title-format" );
973         char *formated = str_format_meta( p_input, format );
974         free( format );
975         aString = [NSString stringWithUTF8String:formated];
976         free( formated );
977
978         char *uri = input_item_GetURI( input_GetItem( p_input ) );
979
980         NSURL * o_url = [NSURL URLWithString: [NSString stringWithUTF8String: uri]];
981         if ([o_url isFileURL])
982             [self setRepresentedURL: o_url];
983         else
984             [self setRepresentedURL: nil];
985         free( uri );
986
987         if ([aString isEqualToString:@""])
988         {
989             if ([o_url isFileURL])
990                 aString = [[NSFileManager defaultManager] displayNameAtPath: [o_url path]];
991             else
992                 aString = [o_url absoluteString];
993         }
994
995         [self setTitle: aString];
996         [o_fspanel setStreamTitle: aString];
997     }
998     else
999     {
1000         [self setTitle: _NS("VLC media player")];
1001         [self setRepresentedURL: nil];
1002     }
1003
1004     [o_pool release];
1005 }
1006
1007 - (void)updateWindow
1008 {
1009     bool b_input = false;
1010     bool b_plmul = false;
1011     bool b_control = false;
1012     bool b_seekable = false;
1013     bool b_chapters = false;
1014
1015     playlist_t * p_playlist = pl_Get( VLCIntf );
1016
1017     PL_LOCK;
1018     b_plmul = playlist_CurrentSize( p_playlist ) > 1;
1019     PL_UNLOCK;
1020
1021     input_thread_t * p_input = playlist_CurrentInput( p_playlist );
1022
1023     bool b_buffering = NO;
1024
1025     if( ( b_input = ( p_input != NULL ) ) )
1026     {
1027         /* seekable streams */
1028         cachedInputState = input_GetState( p_input );
1029         if ( cachedInputState == INIT_S || cachedInputState == OPENING_S )
1030             b_buffering = YES;
1031
1032         /* seekable streams */
1033         b_seekable = var_GetBool( p_input, "can-seek" );
1034
1035         /* check whether slow/fast motion is possible */
1036         b_control = var_GetBool( p_input, "can-rate" );
1037
1038         /* chapters & titles */
1039         //FIXME! b_chapters = p_input->stream.i_area_nb > 1;
1040
1041         if (cachedInputState == PLAYING_S || b_buffering == YES)
1042             [self makeKeyAndOrderFront: nil];
1043         vlc_object_release( p_input );
1044     }
1045
1046     if( b_buffering )
1047     {
1048         [o_progress_bar startAnimation:self];
1049         [o_progress_bar setIndeterminate:YES];
1050         [o_progress_bar setHidden:NO];
1051     } else {
1052         [o_progress_bar stopAnimation:self];
1053         [o_progress_bar setHidden:YES];
1054     }
1055
1056     [o_stop_btn setEnabled: b_input];
1057     [o_fwd_btn setEnabled: (b_seekable || b_plmul || b_chapters)];
1058     [o_bwd_btn setEnabled: (b_seekable || b_plmul || b_chapters)];
1059     [[VLCMainMenu sharedInstance] setRateControlsEnabled: b_control];
1060
1061     [o_time_sld setEnabled: b_seekable];
1062     [self updateTimeSlider];
1063     [o_fspanel setSeekable: b_seekable];
1064
1065     PL_LOCK;
1066     if (playlist_CurrentSize( p_playlist ) >= 1)
1067         [self hideDropZone];
1068     else
1069         [self showDropZone];
1070     PL_UNLOCK;
1071     [o_sidebar_view setNeedsDisplay:YES];
1072 }
1073
1074 - (void)setPause
1075 {
1076     [o_play_btn setImage: o_pause_img];
1077     [o_play_btn setAlternateImage: o_pause_pressed_img];
1078     [o_play_btn setToolTip: _NS("Pause")];
1079     [o_fspanel setPause];
1080 }
1081
1082 - (void)setPlay
1083 {
1084     [o_play_btn setImage: o_play_img];
1085     [o_play_btn setAlternateImage: o_play_pressed_img];
1086     [o_play_btn setToolTip: _NS("Play")];
1087     [o_fspanel setPlay];
1088 }
1089
1090 - (void)drawFancyGradientEffectForTimeSlider
1091 {
1092     if (OSX_LEOPARD)
1093         return;
1094
1095     NSAutoreleasePool * o_pool = [[NSAutoreleasePool alloc] init];
1096     CGFloat f_value = [o_time_sld knobPosition];
1097     if (f_value > 7.5)
1098     {
1099         NSRect oldFrame = [o_time_sld_fancygradient_view frame];
1100         if (f_value != oldFrame.size.width)
1101         {
1102             [o_time_sld_fancygradient_view setHidden: NO];
1103             [o_time_sld_fancygradient_view setFrame: NSMakeRect( oldFrame.origin.x, oldFrame.origin.y, f_value, oldFrame.size.height )];
1104             [o_time_sld_fancygradient_view setNeedsDisplay:YES];
1105         }
1106     }
1107     else
1108     {
1109         [o_time_sld_fancygradient_view setHidden: YES];
1110     }
1111     [o_pool release];
1112 }
1113
1114 #pragma mark -
1115 #pragma mark Video Output handling
1116
1117 - (id)videoView
1118 {
1119     vout_thread_t *p_vout = getVout();
1120     if (config_GetInt( VLCIntf, "embedded-video" ))
1121     {
1122         if ([o_video_view window] != self)
1123         {
1124             [o_video_view removeFromSuperviewWithoutNeedingDisplay];
1125             [o_video_view setFrame: [o_split_view frame]];
1126             [[self contentView] addSubview:o_video_view positioned:NSWindowAbove relativeTo:nil];
1127         }
1128         b_nonembedded = NO;
1129     }
1130     else
1131     {
1132         if ([o_video_view superview] != NULL)
1133             [o_video_view removeFromSuperviewWithoutNeedingDisplay];
1134         if (o_nonembedded_window)
1135             [o_nonembedded_window release];
1136
1137         o_nonembedded_window = [[VLCWindow alloc] initWithContentRect:[o_video_view frame] styleMask: NSTitledWindowMask|NSClosableWindowMask|NSResizableWindowMask|NSMiniaturizableWindowMask backing:NSBackingStoreBuffered defer:YES];
1138         [o_nonembedded_window setFrame:[o_video_view frame] display:NO];
1139         [o_nonembedded_window setBackgroundColor: [NSColor blackColor]];
1140         [o_nonembedded_window setMovableByWindowBackground: YES];
1141         [o_nonembedded_window setCanBecomeKeyWindow: YES];
1142         [o_nonembedded_window setHasShadow:YES];
1143         [o_nonembedded_window setContentView: o_video_view];
1144         [o_nonembedded_window setLevel:NSNormalWindowLevel];
1145         [o_nonembedded_window useOptimizedDrawing: YES];
1146         [o_nonembedded_window center];
1147         [o_nonembedded_window makeKeyAndOrderFront:self];
1148         [o_nonembedded_window orderFront:self animate:YES];
1149         [o_nonembedded_window setReleasedWhenClosed:NO];
1150         b_nonembedded = YES;
1151     }
1152
1153     if (p_vout)
1154     {
1155         if( var_GetBool( p_vout, "video-on-top" ) )
1156             [[o_video_view window] setLevel: NSStatusWindowLevel];
1157         else
1158             [[o_video_view window] setLevel: NSNormalWindowLevel];
1159         vlc_object_release( p_vout );
1160     }
1161     return o_video_view;
1162 }
1163
1164 - (void)setVideoplayEnabled
1165 {
1166     BOOL b_videoPlayback = [[VLCMain sharedInstance] activeVideoPlayback];
1167
1168     if (!b_nonembedded)
1169         [o_playlist_btn setEnabled: b_videoPlayback];
1170     else
1171     {
1172         [o_playlist_btn setEnabled: NO];
1173         if (!b_videoPlayback)
1174             [o_nonembedded_window orderOut: nil];
1175     }
1176     if( OSX_LION && b_nativeFullscreenMode )
1177     {
1178         if( [NSApp presentationOptions] & NSApplicationPresentationFullScreen )
1179             [o_bottombar_view setHidden: b_videoPlayback];
1180         else
1181             [o_bottombar_view setHidden: NO];
1182         if (!b_videoPlayback)
1183             [o_fspanel setNonActive: nil];
1184     }
1185     if (b_videoPlayback)
1186         [self makeFirstResponder: o_video_view];
1187 }
1188
1189 - (void)resizeWindow
1190 {
1191     if ( !b_fullscreen && !(OSX_LION && [NSApp presentationOptions] == NSApplicationPresentationFullScreen && b_nativeFullscreenMode) )
1192     {
1193         NSPoint topleftbase;
1194         NSPoint topleftscreen;
1195         NSRect new_frame;
1196         topleftbase.x = 0;
1197         topleftbase.y = [self frame].size.height;
1198         topleftscreen = [self convertBaseToScreen: topleftbase];
1199
1200         /* Calculate the window's new size */
1201         new_frame.size.width = [self frame].size.width - [o_video_view frame].size.width + nativeVideoSize.width;
1202         if (b_dark_interface)
1203             new_frame.size.height = [self frame].size.height - [o_video_view frame].size.height + nativeVideoSize.height + [o_titlebar_view frame].size.height;
1204         else
1205             new_frame.size.height = [self frame].size.height - [o_video_view frame].size.height + nativeVideoSize.height;
1206
1207         new_frame.origin.x = topleftscreen.x;
1208         new_frame.origin.y = topleftscreen.y - new_frame.size.height;
1209
1210         [[self animator] setFrame:new_frame display:YES];
1211     }
1212 }
1213
1214 - (void)setNativeVideoSize:(NSSize)size
1215 {
1216     if (size.width != nativeVideoSize.width || size.height != nativeVideoSize.height )
1217     {
1218         nativeVideoSize = size;
1219         [self resizeWindow];
1220     }
1221 }
1222
1223 //  Called automatically if window's acceptsMouseMovedEvents property is true
1224 - (void)mouseMoved:(NSEvent *)theEvent
1225 {
1226     if (b_fullscreen)
1227         [self recreateHideMouseTimer];
1228
1229     [super mouseMoved: theEvent];
1230 }
1231
1232 - (void)recreateHideMouseTimer
1233 {
1234     if (t_hide_mouse_timer != nil) {
1235         [t_hide_mouse_timer invalidate];
1236         [t_hide_mouse_timer release];
1237     }
1238
1239     t_hide_mouse_timer = [NSTimer scheduledTimerWithTimeInterval:2
1240                                                           target:self
1241                                                         selector:@selector(hideMouseCursor:)
1242                                                         userInfo:nil
1243                                                          repeats:NO];
1244     [t_hide_mouse_timer retain];
1245 }
1246
1247 //  NSTimer selectors require this function signature as per Apple's docs
1248 - (void)hideMouseCursor:(NSTimer *)timer
1249 {
1250     [NSCursor setHiddenUntilMouseMoves: YES];
1251 }
1252
1253 - (void)someWindowWillClose:(NSNotification *)notification
1254 {
1255     if([notification object] == o_nonembedded_window || [notification object] == self)
1256         [[VLCCoreInteraction sharedInstance] stop];
1257 }
1258
1259 - (void)someWindowWillMiniaturize:(NSNotification *)notification
1260 {
1261     if([notification object] == o_nonembedded_window || [notification object] == self)
1262         [[VLCCoreInteraction sharedInstance] pause];
1263 }
1264
1265 #pragma mark -
1266 #pragma mark Fullscreen support
1267 - (void)showFullscreenController
1268 {
1269      if (b_fullscreen && [[VLCMain sharedInstance] activeVideoPlayback] )
1270         [o_fspanel fadeIn];
1271 }
1272
1273 - (BOOL)isFullscreen
1274 {
1275     return b_fullscreen;
1276 }
1277
1278 - (void)lockFullscreenAnimation
1279 {
1280     [o_animation_lock lock];
1281 }
1282
1283 - (void)unlockFullscreenAnimation
1284 {
1285     [o_animation_lock unlock];
1286 }
1287
1288 - (void)enterFullscreen
1289 {
1290     NSMutableDictionary *dict1, *dict2;
1291     NSScreen *screen;
1292     NSRect screen_rect;
1293     NSRect rect;
1294     vout_thread_t *p_vout = getVout();
1295     BOOL blackout_other_displays = config_GetInt( VLCIntf, "macosx-black" );
1296
1297     if( p_vout )
1298         screen = [NSScreen screenWithDisplayID:(CGDirectDisplayID)config_GetInt( VLCIntf, "macosx-vdev" )];
1299
1300     [self lockFullscreenAnimation];
1301
1302     if (!screen)
1303     {
1304         msg_Dbg( VLCIntf, "chosen screen isn't present, using current screen for fullscreen mode" );
1305         screen = [self screen];
1306     }
1307     if (!screen)
1308     {
1309         msg_Dbg( VLCIntf, "Using deepest screen" );
1310         screen = [NSScreen deepestScreen];
1311     }
1312
1313     if( p_vout )
1314         vlc_object_release( p_vout );
1315
1316     screen_rect = [screen frame];
1317
1318     [o_fullscreen_btn setState: YES];
1319
1320     [self recreateHideMouseTimer];
1321
1322     if( blackout_other_displays )
1323         [screen blackoutOtherScreens];
1324
1325     /* Make sure we don't see the window flashes in float-on-top mode */
1326     i_originalLevel = [self level];
1327     [self setLevel:NSNormalWindowLevel];
1328
1329     /* Only create the o_fullscreen_window if we are not in the middle of the zooming animation */
1330     if (!o_fullscreen_window)
1331     {
1332         /* We can't change the styleMask of an already created NSWindow, so we create another window, and do eye catching stuff */
1333
1334         rect = [[o_video_view superview] convertRect: [o_video_view frame] toView: nil]; /* Convert to Window base coord */
1335         rect.origin.x += [self frame].origin.x;
1336         rect.origin.y += [self frame].origin.y;
1337         o_fullscreen_window = [[VLCWindow alloc] initWithContentRect:rect styleMask: NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:YES];
1338         [o_fullscreen_window setBackgroundColor: [NSColor blackColor]];
1339         [o_fullscreen_window setCanBecomeKeyWindow: YES];
1340
1341         if (![self isVisible] || [self alphaValue] == 0.0)
1342         {
1343             /* We don't animate if we are not visible, instead we
1344              * simply fade the display */
1345             CGDisplayFadeReservationToken token;
1346
1347             if( blackout_other_displays )
1348             {
1349                 CGAcquireDisplayFadeReservation( kCGMaxDisplayReservationInterval, &token );
1350                 CGDisplayFade( token, 0.5, kCGDisplayBlendNormal, kCGDisplayBlendSolidColor, 0, 0, 0, YES );
1351             }
1352
1353             if ([screen isMainScreen])
1354             {
1355                 if (OSX_LEOPARD)
1356                     SetSystemUIMode( kUIModeAllHidden, kUIOptionAutoShowMenuBar);
1357                 else
1358                     [NSApp setPresentationOptions:(NSApplicationPresentationAutoHideDock | NSApplicationPresentationAutoHideMenuBar)];
1359             }
1360
1361             [[o_video_view superview] replaceSubview:o_video_view with:o_temp_view];
1362             [o_temp_view setFrame:[o_video_view frame]];
1363             [o_fullscreen_window setContentView:o_video_view];
1364
1365             [o_fullscreen_window makeKeyAndOrderFront:self];
1366             [o_fullscreen_window orderFront:self animate:YES];
1367
1368             [o_fullscreen_window setFrame:screen_rect display:YES animate:YES];
1369             [o_fullscreen_window setLevel:NSNormalWindowLevel];
1370
1371             if( blackout_other_displays )
1372             {
1373                 CGDisplayFade( token, 0.3, kCGDisplayBlendSolidColor, kCGDisplayBlendNormal, 0, 0, 0, NO );
1374                 CGReleaseDisplayFadeReservation( token );
1375             }
1376
1377             /* Will release the lock */
1378             [self hasBecomeFullscreen];
1379
1380             return;
1381         }
1382
1383         /* Make sure we don't see the o_video_view disappearing of the screen during this operation */
1384         NSDisableScreenUpdates();
1385         [[o_video_view superview] replaceSubview:o_video_view with:o_temp_view];
1386         [o_temp_view setFrame:[o_video_view frame]];
1387         [o_fullscreen_window setContentView:o_video_view];
1388         [o_fullscreen_window makeKeyAndOrderFront:self];
1389         NSEnableScreenUpdates();
1390     }
1391
1392     /* We are in fullscreen (and no animation is running) */
1393     if (b_fullscreen)
1394     {
1395         /* Make sure we are hidden */
1396         [super orderOut: self];
1397         [self unlockFullscreenAnimation];
1398         return;
1399     }
1400
1401     if (o_fullscreen_anim1)
1402     {
1403         [o_fullscreen_anim1 stopAnimation];
1404         [o_fullscreen_anim1 release];
1405     }
1406     if (o_fullscreen_anim2)
1407     {
1408         [o_fullscreen_anim2 stopAnimation];
1409         [o_fullscreen_anim2 release];
1410     }
1411
1412     if ([screen isMainScreen])
1413     {
1414         if (OSX_LEOPARD)
1415             SetSystemUIMode( kUIModeAllHidden, kUIOptionAutoShowMenuBar);
1416         else
1417             [NSApp setPresentationOptions:(NSApplicationPresentationAutoHideDock | NSApplicationPresentationAutoHideMenuBar)];
1418     }
1419
1420     dict1 = [[NSMutableDictionary alloc] initWithCapacity:2];
1421     dict2 = [[NSMutableDictionary alloc] initWithCapacity:3];
1422
1423     [dict1 setObject:self forKey:NSViewAnimationTargetKey];
1424     [dict1 setObject:NSViewAnimationFadeOutEffect forKey:NSViewAnimationEffectKey];
1425
1426     [dict2 setObject:o_fullscreen_window forKey:NSViewAnimationTargetKey];
1427     [dict2 setObject:[NSValue valueWithRect:[o_fullscreen_window frame]] forKey:NSViewAnimationStartFrameKey];
1428     [dict2 setObject:[NSValue valueWithRect:screen_rect] forKey:NSViewAnimationEndFrameKey];
1429
1430     /* Strategy with NSAnimation allocation:
1431      - Keep at most 2 animation at a time
1432      - leaveFullscreen/enterFullscreen are the only responsible for releasing and alloc-ing
1433      */
1434     o_fullscreen_anim1 = [[NSViewAnimation alloc] initWithViewAnimations:[NSArray arrayWithObject:dict1]];
1435     o_fullscreen_anim2 = [[NSViewAnimation alloc] initWithViewAnimations:[NSArray arrayWithObject:dict2]];
1436
1437     [dict1 release];
1438     [dict2 release];
1439
1440     [o_fullscreen_anim1 setAnimationBlockingMode: NSAnimationNonblocking];
1441     [o_fullscreen_anim1 setDuration: 0.3];
1442     [o_fullscreen_anim1 setFrameRate: 30];
1443     [o_fullscreen_anim2 setAnimationBlockingMode: NSAnimationNonblocking];
1444     [o_fullscreen_anim2 setDuration: 0.2];
1445     [o_fullscreen_anim2 setFrameRate: 30];
1446
1447     [o_fullscreen_anim2 setDelegate: self];
1448     [o_fullscreen_anim2 startWhenAnimation: o_fullscreen_anim1 reachesProgress: 1.0];
1449
1450     [o_fullscreen_anim1 startAnimation];
1451     /* fullscreenAnimation will be unlocked when animation ends */
1452 }
1453
1454 - (void)hasBecomeFullscreen
1455 {
1456     [o_fullscreen_window makeFirstResponder: o_video_view];
1457
1458     [o_fullscreen_window makeKeyWindow];
1459     [o_fullscreen_window setAcceptsMouseMovedEvents: TRUE];
1460
1461     /* tell the fspanel to move itself to front next time it's triggered */
1462     [o_fspanel setVoutWasUpdated: (int)[[o_fullscreen_window screen] displayID]];
1463     [o_fspanel setActive: nil];
1464
1465     if([self isVisible])
1466         [super orderOut: self];
1467
1468     [o_fspanel setActive: nil];
1469
1470     b_fullscreen = YES;
1471     [self unlockFullscreenAnimation];
1472 }
1473
1474 - (void)leaveFullscreen
1475 {
1476     [self leaveFullscreenAndFadeOut: NO];
1477 }
1478
1479 - (void)leaveFullscreenAndFadeOut: (BOOL)fadeout
1480 {
1481     NSMutableDictionary *dict1, *dict2;
1482     NSRect frame;
1483     BOOL blackout_other_displays = config_GetInt( VLCIntf, "macosx-black" );
1484
1485     [self lockFullscreenAnimation];
1486
1487     b_fullscreen = NO;
1488     [o_fullscreen_btn setState: NO];
1489
1490     /* We always try to do so */
1491     if (!(OSX_LION && b_nativeFullscreenMode))
1492         [NSScreen unblackoutScreens];
1493     vout_thread_t *p_vout = getVout();
1494     if (p_vout)
1495     {
1496         if( var_GetBool( p_vout, "video-on-top" ) )
1497             [[o_video_view window] setLevel: NSStatusWindowLevel];
1498         else
1499             [[o_video_view window] setLevel: NSNormalWindowLevel];
1500         vlc_object_release( p_vout );
1501     }
1502     [[o_video_view window] makeKeyAndOrderFront: nil];
1503
1504     /* Don't do anything if o_fullscreen_window is already closed */
1505     if (!o_fullscreen_window)
1506     {
1507         [self unlockFullscreenAnimation];
1508         return;
1509     }
1510
1511     if (fadeout)
1512     {
1513         /* We don't animate if we are not visible, instead we
1514          * simply fade the display */
1515         CGDisplayFadeReservationToken token;
1516
1517         if( blackout_other_displays )
1518         {
1519             CGAcquireDisplayFadeReservation( kCGMaxDisplayReservationInterval, &token );
1520             CGDisplayFade( token, 0.3, kCGDisplayBlendNormal, kCGDisplayBlendSolidColor, 0, 0, 0, YES );
1521         }
1522
1523         [o_fspanel setNonActive: nil];
1524         if (OSX_LEOPARD)
1525             SetSystemUIMode( kUIModeNormal, kUIOptionAutoShowMenuBar);
1526         else
1527             [NSApp setPresentationOptions:(NSApplicationPresentationDefault)];
1528
1529         /* Will release the lock */
1530         [self hasEndedFullscreen];
1531
1532         /* Our window is hidden, and might be faded. We need to workaround that, so note it
1533          * here */
1534         b_window_is_invisible = YES;
1535
1536         if( blackout_other_displays )
1537         {
1538             CGDisplayFade( token, 0.5, kCGDisplayBlendSolidColor, kCGDisplayBlendNormal, 0, 0, 0, NO );
1539             CGReleaseDisplayFadeReservation( token );
1540         }
1541
1542         return;
1543     }
1544
1545     [self setAlphaValue: 0.0];
1546     [self orderFront: self];
1547     [[o_video_view window] orderFront: self];
1548
1549     [o_fspanel setNonActive: nil];
1550     if (OSX_LEOPARD)
1551         SetSystemUIMode( kUIModeNormal, kUIOptionAutoShowMenuBar);
1552     else
1553         [NSApp setPresentationOptions:(NSApplicationPresentationDefault)];
1554
1555     if (o_fullscreen_anim1)
1556     {
1557         [o_fullscreen_anim1 stopAnimation];
1558         [o_fullscreen_anim1 release];
1559     }
1560     if (o_fullscreen_anim2)
1561     {
1562         [o_fullscreen_anim2 stopAnimation];
1563         [o_fullscreen_anim2 release];
1564     }
1565
1566     frame = [[o_temp_view superview] convertRect: [o_temp_view frame] toView: nil]; /* Convert to Window base coord */
1567     frame.origin.x += [self frame].origin.x;
1568     frame.origin.y += [self frame].origin.y;
1569
1570     dict2 = [[NSMutableDictionary alloc] initWithCapacity:2];
1571     [dict2 setObject:self forKey:NSViewAnimationTargetKey];
1572     [dict2 setObject:NSViewAnimationFadeInEffect forKey:NSViewAnimationEffectKey];
1573
1574     o_fullscreen_anim2 = [[NSViewAnimation alloc] initWithViewAnimations:[NSArray arrayWithObjects:dict2, nil]];
1575     [dict2 release];
1576
1577     [o_fullscreen_anim2 setAnimationBlockingMode: NSAnimationNonblocking];
1578     [o_fullscreen_anim2 setDuration: 0.3];
1579     [o_fullscreen_anim2 setFrameRate: 30];
1580
1581     [o_fullscreen_anim2 setDelegate: self];
1582
1583     dict1 = [[NSMutableDictionary alloc] initWithCapacity:3];
1584
1585     [dict1 setObject:o_fullscreen_window forKey:NSViewAnimationTargetKey];
1586     [dict1 setObject:[NSValue valueWithRect:[o_fullscreen_window frame]] forKey:NSViewAnimationStartFrameKey];
1587     [dict1 setObject:[NSValue valueWithRect:frame] forKey:NSViewAnimationEndFrameKey];
1588
1589     o_fullscreen_anim1 = [[NSViewAnimation alloc] initWithViewAnimations:[NSArray arrayWithObjects:dict1, nil]];
1590     [dict1 release];
1591
1592     [o_fullscreen_anim1 setAnimationBlockingMode: NSAnimationNonblocking];
1593     [o_fullscreen_anim1 setDuration: 0.2];
1594     [o_fullscreen_anim1 setFrameRate: 30];
1595     [o_fullscreen_anim2 startWhenAnimation: o_fullscreen_anim1 reachesProgress: 1.0];
1596
1597     /* Make sure o_fullscreen_window is the frontmost window */
1598     [o_fullscreen_window orderFront: self];
1599
1600     [o_fullscreen_anim1 startAnimation];
1601     /* fullscreenAnimation will be unlocked when animation ends */
1602 }
1603
1604 - (void)hasEndedFullscreen
1605 {
1606     /* This function is private and should be only triggered at the end of the fullscreen change animation */
1607     /* Make sure we don't see the o_video_view disappearing of the screen during this operation */
1608     NSDisableScreenUpdates();
1609     [o_video_view retain];
1610     [o_video_view removeFromSuperviewWithoutNeedingDisplay];
1611     [[o_temp_view superview] replaceSubview:o_temp_view with:o_video_view];
1612     [o_video_view release];
1613     [o_video_view setFrame:[o_temp_view frame]];
1614     [self makeFirstResponder: o_video_view];
1615     if ([self isVisible])
1616         [super makeKeyAndOrderFront:self]; /* our version contains a workaround */
1617     [o_fullscreen_window orderOut: self];
1618     NSEnableScreenUpdates();
1619
1620     [o_fullscreen_window release];
1621     o_fullscreen_window = nil;
1622     [self setLevel:i_originalLevel];
1623
1624     [self unlockFullscreenAnimation];
1625 }
1626
1627 - (void)animationDidEnd:(NSAnimation*)animation
1628 {
1629     NSArray *viewAnimations;
1630     if( o_makekey_anim == animation )
1631     {
1632         [o_makekey_anim release];
1633         return;
1634     }
1635     if ([animation currentValue] < 1.0)
1636         return;
1637
1638     /* Fullscreen ended or started (we are a delegate only for leaveFullscreen's/enterFullscren's anim2) */
1639     viewAnimations = [o_fullscreen_anim2 viewAnimations];
1640     if ([viewAnimations count] >=1 &&
1641         [[[viewAnimations objectAtIndex: 0] objectForKey: NSViewAnimationEffectKey] isEqualToString:NSViewAnimationFadeInEffect])
1642     {
1643         /* Fullscreen ended */
1644         [self hasEndedFullscreen];
1645     }
1646     else
1647     {
1648         /* Fullscreen started */
1649         [self hasBecomeFullscreen];
1650     }
1651 }
1652
1653 - (void)orderOut: (id)sender
1654 {
1655     /* Make sure we leave fullscreen */
1656     if (!(OSX_LION && b_nativeFullscreenMode))
1657         [self leaveFullscreenAndFadeOut: YES];
1658
1659     [super orderOut: sender];
1660 }
1661
1662 - (void)makeKeyAndOrderFront: (id)sender
1663 {
1664     /* Hack
1665      * when we exit fullscreen and fade out, we may endup in
1666      * having a window that is faded. We can't have it fade in unless we
1667      * animate again. */
1668
1669     if(!b_window_is_invisible)
1670     {
1671         /* Make sure we don't do it too much */
1672         [super makeKeyAndOrderFront: sender];
1673         return;
1674     }
1675
1676     [super setAlphaValue:0.0f];
1677     [super makeKeyAndOrderFront: sender];
1678
1679     NSMutableDictionary * dict = [[NSMutableDictionary alloc] initWithCapacity:2];
1680     [dict setObject:self forKey:NSViewAnimationTargetKey];
1681     [dict setObject:NSViewAnimationFadeInEffect forKey:NSViewAnimationEffectKey];
1682
1683     o_makekey_anim = [[NSViewAnimation alloc] initWithViewAnimations:[NSArray arrayWithObject:dict]];
1684     [dict release];
1685
1686     [o_makekey_anim setAnimationBlockingMode: NSAnimationNonblocking];
1687     [o_makekey_anim setDuration: 0.1];
1688     [o_makekey_anim setFrameRate: 30];
1689     [o_makekey_anim setDelegate: self];
1690
1691     [o_makekey_anim startAnimation];
1692     b_window_is_invisible = NO;
1693
1694     /* fullscreenAnimation will be unlocked when animation ends */
1695 }
1696
1697 /* Make sure setFrame gets executed on main thread especially if we are animating.
1698  * (Thus we won't block the video output thread) */
1699 - (void)setFrame:(NSRect)frame display:(BOOL)display animate:(BOOL)animate
1700 {
1701     struct { NSRect frame; BOOL display; BOOL animate;} args;
1702     NSData *packedargs;
1703
1704     args.frame = frame;
1705     args.display = display;
1706     args.animate = animate;
1707
1708     packedargs = [NSData dataWithBytes:&args length:sizeof(args)];
1709
1710     [self performSelectorOnMainThread:@selector(setFrameOnMainThread:)
1711                            withObject: packedargs waitUntilDone: YES];
1712 }
1713
1714 - (void)setFrameOnMainThread:(NSData*)packedargs
1715 {
1716     struct args { NSRect frame; BOOL display; BOOL animate; } * args = (struct args*)[packedargs bytes];
1717
1718     if( args->animate )
1719     {
1720         /* Make sure we don't block too long and set up a non blocking animation */
1721         NSDictionary * dict = [NSDictionary dictionaryWithObjectsAndKeys:
1722                                self, NSViewAnimationTargetKey,
1723                                [NSValue valueWithRect:[self frame]], NSViewAnimationStartFrameKey,
1724                                [NSValue valueWithRect:args->frame], NSViewAnimationEndFrameKey, nil];
1725
1726         NSViewAnimation * anim = [[NSViewAnimation alloc] initWithViewAnimations:[NSArray arrayWithObject:dict]];
1727
1728         [anim setAnimationBlockingMode: NSAnimationNonblocking];
1729         [anim setDuration: 0.4];
1730         [anim setFrameRate: 30];
1731         [anim startAnimation];
1732
1733         [anim release];
1734     }
1735     else {
1736         [super setFrame:args->frame display:args->display animate:args->animate];
1737     }
1738 }
1739
1740 #pragma mark -
1741 #pragma mark Lion's native fullscreen handling
1742 - (void)windowWillEnterFullScreen:(NSNotification *)notification
1743 {
1744     [o_video_view setFrame: [[self contentView] frame]];
1745     b_fullscreen = YES;
1746     [o_fspanel setVoutWasUpdated: (int)[[self screen] displayID]];
1747
1748     [self recreateHideMouseTimer];
1749
1750     if (b_dark_interface)
1751     {
1752         [o_titlebar_view removeFromSuperviewWithoutNeedingDisplay];
1753
1754         NSRect winrect;
1755         CGFloat f_titleBarHeight = [o_titlebar_view frame].size.height;
1756         winrect = [self frame];
1757
1758         winrect.size.height = winrect.size.height - f_titleBarHeight;
1759         [self setFrame: winrect display:NO animate:NO];
1760         winrect = [o_split_view frame];
1761         winrect.size.height = winrect.size.height + f_titleBarHeight;
1762         [o_split_view setFrame: winrect];
1763     }
1764
1765     if ([[VLCMain sharedInstance] activeVideoPlayback])
1766         [o_bottombar_view setHidden: YES];
1767 }
1768
1769 - (void)windowWillExitFullScreen:(NSNotification *)notification
1770 {
1771     [o_video_view setFrame: [o_split_view frame]];
1772     [NSCursor setHiddenUntilMouseMoves: NO];
1773     [o_fspanel setNonActive: nil];
1774     b_fullscreen = NO;
1775
1776     if (b_dark_interface)
1777     {
1778         NSRect winrect;
1779         CGFloat f_titleBarHeight = [o_titlebar_view frame].size.height;
1780         winrect = [self frame];
1781         
1782         [o_titlebar_view setFrame: NSMakeRect( 0, winrect.size.height - f_titleBarHeight,
1783                                               winrect.size.width, f_titleBarHeight )];
1784         [[self contentView] addSubview: o_titlebar_view];
1785         
1786         winrect.size.height = winrect.size.height + f_titleBarHeight;
1787         [self setFrame: winrect display:NO animate:NO];
1788         winrect = [o_split_view frame];
1789         winrect.size.height = winrect.size.height - f_titleBarHeight;
1790         [o_split_view setFrame: winrect];
1791         [o_video_view setFrame: winrect];
1792     }
1793
1794     if ([[VLCMain sharedInstance] activeVideoPlayback])
1795         [o_bottombar_view setHidden: NO];
1796 }
1797
1798 #pragma mark -
1799 #pragma mark split view delegate
1800 - (CGFloat)splitView:(NSSplitView *)splitView constrainMinCoordinate:(CGFloat)proposedMin ofSubviewAt:(NSInteger)dividerIndex
1801 {
1802     if (dividerIndex == 0)
1803         return 200.0;
1804     else
1805         return proposedMin;
1806 }
1807
1808 - (CGFloat)splitView:(NSSplitView *)splitView constrainMaxCoordinate:(CGFloat)proposedMax ofSubviewAt:(NSInteger)dividerIndex
1809 {
1810     if (dividerIndex == 0)
1811         return ([self frame].size.width - 300.0);
1812     else
1813         return proposedMax;
1814 }
1815
1816 #pragma mark -
1817 #pragma mark Side Bar Data handling
1818 /* taken under BSD-new from the PXSourceList sample project, adapted for VLC */
1819 - (NSUInteger)sourceList:(PXSourceList*)sourceList numberOfChildrenOfItem:(id)item
1820 {
1821         //Works the same way as the NSOutlineView data source: `nil` means a parent item
1822         if(item==nil) {
1823                 return [o_sidebaritems count];
1824         }
1825         else {
1826                 return [[item children] count];
1827         }
1828 }
1829
1830
1831 - (id)sourceList:(PXSourceList*)aSourceList child:(NSUInteger)index ofItem:(id)item
1832 {
1833     //Works the same way as the NSOutlineView data source: `nil` means a parent item
1834         if(item==nil) {
1835                 return [o_sidebaritems objectAtIndex:index];
1836         }
1837         else {
1838                 return [[item children] objectAtIndex:index];
1839         }
1840 }
1841
1842
1843 - (id)sourceList:(PXSourceList*)aSourceList objectValueForItem:(id)item
1844 {
1845         return [item title];
1846 }
1847
1848 - (void)sourceList:(PXSourceList*)aSourceList setObjectValue:(id)object forItem:(id)item
1849 {
1850         [item setTitle:object];
1851 }
1852
1853 - (BOOL)sourceList:(PXSourceList*)aSourceList isItemExpandable:(id)item
1854 {
1855         return [item hasChildren];
1856 }
1857
1858
1859 - (BOOL)sourceList:(PXSourceList*)aSourceList itemHasBadge:(id)item
1860 {
1861     if ([[item identifier] isEqualToString: @"playlist"])
1862         return YES;
1863
1864         return [item hasBadge];
1865 }
1866
1867
1868 - (NSInteger)sourceList:(PXSourceList*)aSourceList badgeValueForItem:(id)item
1869 {
1870     if ([[item identifier] isEqualToString: @"playlist"]) {
1871         playlist_t * p_playlist = pl_Get( VLCIntf );
1872         NSInteger i_playlist_size;
1873
1874         PL_LOCK;
1875         i_playlist_size = p_playlist->items.i_size;
1876         PL_UNLOCK;
1877
1878         return i_playlist_size;
1879     }
1880         return [item badgeValue];
1881 }
1882
1883
1884 - (BOOL)sourceList:(PXSourceList*)aSourceList itemHasIcon:(id)item
1885 {
1886         return [item hasIcon];
1887 }
1888
1889
1890 - (NSImage*)sourceList:(PXSourceList*)aSourceList iconForItem:(id)item
1891 {
1892         return [item icon];
1893 }
1894
1895 - (NSMenu*)sourceList:(PXSourceList*)aSourceList menuForEvent:(NSEvent*)theEvent item:(id)item
1896 {
1897         if ([theEvent type] == NSRightMouseDown || ([theEvent type] == NSLeftMouseDown && ([theEvent modifierFlags] & NSControlKeyMask) == NSControlKeyMask)) {
1898                 NSMenu * m = [[NSMenu alloc] init];
1899                 if (item != nil)
1900                         [m addItemWithTitle:[item title] action:nil keyEquivalent:@""];
1901                 return [m autorelease];
1902         }
1903         return nil;
1904 }
1905
1906 #pragma mark -
1907 #pragma mark Side Bar Delegate Methods
1908 /* taken under BSD-new from the PXSourceList sample project, adapted for VLC */
1909 - (BOOL)sourceList:(PXSourceList*)aSourceList isGroupAlwaysExpanded:(id)group
1910 {
1911     return NO;
1912 }
1913
1914 - (void)sourceListSelectionDidChange:(NSNotification *)notification
1915 {
1916         NSIndexSet *selectedIndexes = [o_sidebar_view selectedRowIndexes];
1917
1918         //Set the label text to represent the new selection
1919     if([selectedIndexes count]==1) {
1920                 NSString *title = [[o_sidebar_view itemAtRow:[selectedIndexes firstIndex]] title];
1921
1922                 [o_chosen_category_lbl setStringValue:title];
1923         }
1924         else {
1925                 [o_chosen_category_lbl setStringValue:@"(none)"];
1926         }
1927 }
1928
1929 @end