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