macosx: activate app when going to fullscreen
[vlc.git] / 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 "playlist.h"
36 #import "SideBarItem.h"
37 #import <math.h>
38 #import <vlc_playlist.h>
39 #import <vlc_aout_intf.h>
40 #import <vlc_url.h>
41 #import <vlc_strings.h>
42 #import <vlc_services_discovery.h>
43 #import <vlc_aout_intf.h>
44
45 @implementation VLCMainWindow
46 static const float f_min_video_height = 70.0;
47
48 static VLCMainWindow *_o_sharedInstance = nil;
49
50 + (VLCMainWindow *)sharedInstance
51 {
52     return _o_sharedInstance ? _o_sharedInstance : [[self alloc] init];
53 }
54
55 #pragma mark -
56 #pragma mark Initialization
57
58 - (id)init
59 {
60     if( _o_sharedInstance )
61     {
62         [self dealloc];
63         return _o_sharedInstance;
64     }
65     else
66     {
67         _o_sharedInstance = [super init];
68     }
69
70     return _o_sharedInstance;
71 }
72
73 - (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)styleMask
74                   backing:(NSBackingStoreType)backingType defer:(BOOL)flag
75 {
76     b_dark_interface = config_GetInt( VLCIntf, "macosx-interfacestyle" );
77
78     if (b_dark_interface)
79     {
80 #ifdef MAC_OS_X_VERSION_10_7
81         if (OSX_LION)
82             styleMask = NSBorderlessWindowMask | NSResizableWindowMask;
83         else
84             styleMask = NSBorderlessWindowMask;
85 #else
86         styleMask = NSBorderlessWindowMask;
87 #endif
88     }
89
90     self = [super initWithContentRect:contentRect styleMask:styleMask
91                               backing:backingType defer:flag];
92     _o_sharedInstance = self;
93
94     [[VLCMain sharedInstance] updateTogglePlaylistState];
95
96     /* we want to be moveable regardless of our style */
97     [self setMovableByWindowBackground: YES];
98
99     /* we don't want this window to be restored on relaunch */
100     if (OSX_LION)
101         [self setRestorable:NO];
102
103     return self;
104 }
105
106 - (BOOL)isEvent:(NSEvent *)o_event forKey:(const char *)keyString
107 {
108     char *key;
109     NSString *o_key;
110
111     key = config_GetPsz( VLCIntf, keyString );
112     o_key = [NSString stringWithFormat:@"%s", key];
113     FREENULL( key );
114
115     unsigned int i_keyModifiers = [[VLCMain sharedInstance] VLCModifiersToCocoa:o_key];
116
117     return [[[o_event charactersIgnoringModifiers] lowercaseString] isEqualToString: [[VLCMain sharedInstance] VLCKeyToString: o_key]] &&
118             (i_keyModifiers & NSShiftKeyMask)     == ([o_event modifierFlags] & NSShiftKeyMask) &&
119             (i_keyModifiers & NSControlKeyMask)   == ([o_event modifierFlags] & NSControlKeyMask) &&
120             (i_keyModifiers & NSAlternateKeyMask) == ([o_event modifierFlags] & NSAlternateKeyMask) &&
121             (i_keyModifiers & NSCommandKeyMask)   == ([o_event modifierFlags] & NSCommandKeyMask);
122 }
123
124 - (BOOL)performKeyEquivalent:(NSEvent *)o_event
125 {
126     BOOL b_force = NO;
127     // these are key events which should be handled by vlc core, but are attached to a main menu item
128     if( ![self isEvent: o_event forKey: "key-vol-up"] &&
129         ![self isEvent: o_event forKey: "key-vol-down"] &&
130         ![self isEvent: o_event forKey: "key-vol-mute"] )
131     {
132         /* We indeed want to prioritize some Cocoa key equivalent against libvlc,
133          so we perform the menu equivalent now. */
134         if([[NSApp mainMenu] performKeyEquivalent:o_event])
135             return TRUE;
136     }
137     else
138         b_force = YES;
139
140     return [[VLCMain sharedInstance] hasDefinedShortcutKey:o_event force:b_force] ||
141            [(VLCControls *)[[VLCMain sharedInstance] controls] keyEvent:o_event];
142 }
143
144 - (void)dealloc
145 {
146     if (b_dark_interface)
147         [o_color_backdrop release];
148
149     [[NSNotificationCenter defaultCenter] removeObserver: self];
150     [o_sidebaritems release];
151     [super dealloc];
152 }
153
154 - (void)awakeFromNib
155 {
156     BOOL b_splitviewShouldBeHidden = NO;
157
158     /* setup the styled interface */
159     b_video_deco = config_GetInt( VLCIntf, "video-deco" );
160     b_nativeFullscreenMode = NO;
161 #ifdef MAC_OS_X_VERSION_10_7
162     if( OSX_LION && b_video_deco )
163         b_nativeFullscreenMode = config_GetInt( VLCIntf, "macosx-nativefullscreenmode" );
164 #endif
165     t_hide_mouse_timer = nil;
166     [o_detached_video_window setDelegate: self];
167     [self useOptimizedDrawing: YES];
168
169     [o_play_btn setToolTip: _NS("Play/Pause")];
170     [o_detached_play_btn setToolTip: [o_play_btn toolTip]];
171     [o_bwd_btn setToolTip: _NS("Backward")];
172     [o_detached_bwd_btn setToolTip: [o_bwd_btn toolTip]];
173     [o_fwd_btn setToolTip: _NS("Forward")];
174     [o_detached_fwd_btn setToolTip: [o_fwd_btn toolTip]];
175     [o_stop_btn setToolTip: _NS("Stop")];
176     [o_playlist_btn setToolTip: _NS("Show/Hide Playlist")];
177     [o_repeat_btn setToolTip: _NS("Repeat")];
178     [o_shuffle_btn setToolTip: _NS("Shuffle")];
179     [o_effects_btn setToolTip: _NS("Effects")];
180     [o_fullscreen_btn setToolTip: _NS("Toggle Fullscreen mode")];
181     [o_detached_fullscreen_btn setToolTip: [o_fullscreen_btn toolTip]];
182     [[o_search_fld cell] setPlaceholderString: _NS("Search")];
183     [o_volume_sld setToolTip: _NS("Volume")];
184     [o_volume_down_btn setToolTip: _NS("Mute")];
185     [o_volume_up_btn setToolTip: _NS("Full Volume")];
186     [o_time_sld setToolTip: _NS("Position")];
187     [o_detached_time_sld setToolTip: [o_time_sld toolTip]];
188     [o_dropzone_btn setTitle: _NS("Open media...")];
189     [o_dropzone_lbl setStringValue: _NS("Drop media here")];
190
191     if (!b_dark_interface) {
192         [o_bottombar_view setImagesLeft: [NSImage imageNamed:@"bottom-background"] middle: [NSImage imageNamed:@"bottom-background"] right: [NSImage imageNamed:@"bottom-background"]];
193         [o_detached_bottombar_view setImagesLeft: [NSImage imageNamed:@"bottom-background"] middle: [NSImage imageNamed:@"bottom-background"] right: [NSImage imageNamed:@"bottom-background"]];
194         [o_bwd_btn setImage: [NSImage imageNamed:@"back"]];
195         [o_bwd_btn setAlternateImage: [NSImage imageNamed:@"back-pressed"]];
196         [o_detached_bwd_btn setImage: [NSImage imageNamed:@"back"]];
197         [o_detached_bwd_btn setAlternateImage: [NSImage imageNamed:@"back-pressed"]];
198         o_play_img = [[NSImage imageNamed:@"play"] retain];
199         o_play_pressed_img = [[NSImage imageNamed:@"play-pressed"] retain];
200         o_pause_img = [[NSImage imageNamed:@"pause"] retain];
201         o_pause_pressed_img = [[NSImage imageNamed:@"pause-pressed"] retain];
202         [o_fwd_btn setImage: [NSImage imageNamed:@"forward"]];
203         [o_fwd_btn setAlternateImage: [NSImage imageNamed:@"forward-pressed"]];
204         [o_detached_fwd_btn setImage: [NSImage imageNamed:@"forward"]];
205         [o_detached_fwd_btn setAlternateImage: [NSImage imageNamed:@"forward-pressed"]];
206         [o_stop_btn setImage: [NSImage imageNamed:@"stop"]];
207         [o_stop_btn setAlternateImage: [NSImage imageNamed:@"stop-pressed"]];
208         [o_playlist_btn setImage: [NSImage imageNamed:@"playlist-btn"]];
209         [o_playlist_btn setAlternateImage: [NSImage imageNamed:@"playlist-btn-pressed"]];
210         o_repeat_img = [[NSImage imageNamed:@"repeat"] retain];
211         o_repeat_pressed_img = [[NSImage imageNamed:@"repeat-pressed"] retain];
212         o_repeat_all_img  = [[NSImage imageNamed:@"repeat-all"] retain];
213         o_repeat_all_pressed_img = [[NSImage imageNamed:@"repeat-all-pressed"] retain];
214         o_repeat_one_img = [[NSImage imageNamed:@"repeat-one"] retain];
215         o_repeat_one_pressed_img = [[NSImage imageNamed:@"repeat-one-pressed"] retain];
216         o_shuffle_img = [[NSImage imageNamed:@"shuffle"] retain];
217         o_shuffle_pressed_img = [[NSImage imageNamed:@"shuffle-pressed"] retain];
218         o_shuffle_on_img = [[NSImage imageNamed:@"shuffle-blue"] retain];
219         o_shuffle_on_pressed_img = [[NSImage imageNamed:@"shuffle-blue-pressed"] retain];
220         [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"]];
221         [o_detached_time_sld_background setImagesLeft: [NSImage imageNamed:@"progression-track-wrapper-left"] middle: [NSImage imageNamed:@"progression-track-wrapper-middle"] right: [NSImage imageNamed:@"progression-track-wrapper-right"]];
222         [o_volume_down_btn setImage: [NSImage imageNamed:@"volume-low"]];
223         [o_volume_track_view setImage: [NSImage imageNamed:@"volume-slider-track"]];
224         [o_volume_up_btn setImage: [NSImage imageNamed:@"volume-high"]];
225         if (b_nativeFullscreenMode)
226         {
227             [o_effects_btn setImage: [NSImage imageNamed:@"effects-one-button"]];
228             [o_effects_btn setAlternateImage: [NSImage imageNamed:@"effects-one-button-blue"]];
229         }
230         else
231         {
232             [o_effects_btn setImage: [NSImage imageNamed:@"effects-double-buttons"]];
233             [o_effects_btn setAlternateImage: [NSImage imageNamed:@"effects-double-buttons-pressed"]];
234         }
235         [o_fullscreen_btn setImage: [NSImage imageNamed:@"fullscreen-double-buttons"]];
236         [o_fullscreen_btn setAlternateImage: [NSImage imageNamed:@"fullscreen-double-buttons-pressed"]];
237         [o_detached_fullscreen_btn setImage: [NSImage imageNamed:@"fullscreen-one-button"]];
238         [o_detached_fullscreen_btn setAlternateImage: [NSImage imageNamed:@"fullscreen-one-button-pressed"]];
239         [o_time_sld_fancygradient_view setImagesLeft:[NSImage imageNamed:@"progression-fill-left"] middle:[NSImage imageNamed:@"progression-fill-middle"] right:[NSImage imageNamed:@"progression-fill-right"]];
240         [o_detached_time_sld_fancygradient_view setImagesLeft:[NSImage imageNamed:@"progression-fill-left"] middle:[NSImage imageNamed:@"progression-fill-middle"] right:[NSImage imageNamed:@"progression-fill-right"]];
241     }
242     else
243     {
244         [o_bottombar_view setImagesLeft: [NSImage imageNamed:@"bottomdark-left"] middle: [NSImage imageNamed:@"bottom-background_dark"] right: [NSImage imageNamed:@"bottomdark-right"]];
245         [o_detached_bottombar_view setImagesLeft: [NSImage imageNamed:@"bottomdark-left"] middle: [NSImage imageNamed:@"bottom-background_dark"] right: [NSImage imageNamed:@"bottomdark-right"]];
246         [o_bwd_btn setImage: [NSImage imageNamed:@"back_dark"]];
247         [o_bwd_btn setAlternateImage: [NSImage imageNamed:@"back-pressed_dark"]];
248         [o_detached_bwd_btn setImage: [NSImage imageNamed:@"back_dark"]];
249         [o_detached_bwd_btn setAlternateImage: [NSImage imageNamed:@"back-pressed_dark"]];
250         o_play_img = [[NSImage imageNamed:@"play_dark"] retain];
251         o_play_pressed_img = [[NSImage imageNamed:@"play-pressed_dark"] retain];
252         o_pause_img = [[NSImage imageNamed:@"pause_dark"] retain];
253         o_pause_pressed_img = [[NSImage imageNamed:@"pause-pressed_dark"] retain];
254         [o_fwd_btn setImage: [NSImage imageNamed:@"forward_dark"]];
255         [o_fwd_btn setAlternateImage: [NSImage imageNamed:@"forward-pressed_dark"]];
256         [o_detached_fwd_btn setImage: [NSImage imageNamed:@"forward_dark"]];
257         [o_detached_fwd_btn setAlternateImage: [NSImage imageNamed:@"forward-pressed_dark"]];
258         [o_stop_btn setImage: [NSImage imageNamed:@"stop_dark"]];
259         [o_stop_btn setAlternateImage: [NSImage imageNamed:@"stop-pressed_dark"]];
260         [o_playlist_btn setImage: [NSImage imageNamed:@"playlist_dark"]];
261         [o_playlist_btn setAlternateImage: [NSImage imageNamed:@"playlist-pressed_dark"]];
262         o_repeat_img = [[NSImage imageNamed:@"repeat_dark"] retain];
263         o_repeat_pressed_img = [[NSImage imageNamed:@"repeat-pressed_dark"] retain];
264         o_repeat_all_img  = [[NSImage imageNamed:@"repeat-all-blue_dark"] retain];
265         o_repeat_all_pressed_img = [[NSImage imageNamed:@"repeat-all-blue-pressed_dark"] retain];
266         o_repeat_one_img = [[NSImage imageNamed:@"repeat-one-blue_dark"] retain];
267         o_repeat_one_pressed_img = [[NSImage imageNamed:@"repeat-one-blue-pressed_dark"] retain];
268         o_shuffle_img = [[NSImage imageNamed:@"shuffle_dark"] retain];
269         o_shuffle_pressed_img = [[NSImage imageNamed:@"shuffle-pressed_dark"] retain];
270         o_shuffle_on_img = [[NSImage imageNamed:@"shuffle-blue_dark"] retain];
271         o_shuffle_on_pressed_img = [[NSImage imageNamed:@"shuffle-blue-pressed_dark"] retain];
272         [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"]];
273         [o_detached_time_sld_background setImagesLeft: [NSImage imageNamed:@"progression-track-wrapper-left_dark"] middle: [NSImage imageNamed:@"progression-track-wrapper-middle_dark"] right: [NSImage imageNamed:@"progression-track-wrapper-right_dark"]];
274         [o_volume_down_btn setImage: [NSImage imageNamed:@"volume-low_dark"]];
275         [o_volume_track_view setImage: [NSImage imageNamed:@"volume-slider-track_dark"]];
276         [o_volume_up_btn setImage: [NSImage imageNamed:@"volume-high_dark"]];
277         if (b_nativeFullscreenMode)
278         {
279             [o_effects_btn setImage: [NSImage imageNamed:@"effects-one-button_dark"]];
280             [o_effects_btn setAlternateImage: [NSImage imageNamed:@"effects-one-button-blue_dark"]];
281         }
282         else
283         {
284             [o_effects_btn setImage: [NSImage imageNamed:@"effects-double-buttons_dark"]];
285             [o_effects_btn setAlternateImage: [NSImage imageNamed:@"effects-double-buttons-pressed_dark"]];
286         }
287         [o_fullscreen_btn setImage: [NSImage imageNamed:@"fullscreen-double-buttons_dark"]];
288         [o_fullscreen_btn setAlternateImage: [NSImage imageNamed:@"fullscreen-double-buttons-pressed_dark"]];
289         [o_detached_fullscreen_btn setImage: [NSImage imageNamed:@"fullscreen-one-button_dark"]];
290         [o_detached_fullscreen_btn setAlternateImage: [NSImage imageNamed:@"fullscreen-one-button-pressed_dark"]];
291         [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"]];
292         [o_detached_time_sld_fancygradient_view setImagesLeft:[NSImage imageNamed:@"progressbar-fill-left_dark"] middle:[NSImage imageNamed:@"progressbar-fill-middle_dark"] right:[NSImage imageNamed:@"progressbar-fill-right_dark"]];
293     }
294     [o_repeat_btn setImage: o_repeat_img];
295     [o_repeat_btn setAlternateImage: o_repeat_pressed_img];
296     [o_shuffle_btn setImage: o_shuffle_img];
297     [o_shuffle_btn setAlternateImage: o_shuffle_pressed_img];
298     [o_play_btn setImage: o_play_img];
299     [o_play_btn setAlternateImage: o_play_pressed_img];
300     [o_detached_play_btn setImage: o_play_img];
301     [o_detached_play_btn setAlternateImage: o_play_pressed_img];
302     BOOL b_mute = ![[VLCCoreInteraction sharedInstance] isMuted];
303     [o_volume_sld setEnabled: b_mute];
304     [o_volume_up_btn setEnabled: b_mute];
305
306     b_show_jump_buttons = config_GetInt( VLCIntf, "macosx-show-playback-buttons" );
307     if (b_show_jump_buttons)
308         [self addJumpButtons];
309
310     /* interface builder action */
311     float f_threshold_height = f_min_video_height + [o_bottombar_view frame].size.height;
312     if( b_dark_interface )
313         f_threshold_height += [o_titlebar_view frame].size.height;
314     if( [[self contentView] frame].size.height < f_threshold_height )
315         b_splitviewShouldBeHidden = YES;
316
317     [self setDelegate: self];
318     [self setExcludedFromWindowsMenu: YES];
319     [self setAcceptsMouseMovedEvents: YES];
320     // Set that here as IB seems to be buggy
321     if (b_dark_interface && b_video_deco)
322     {
323         [self setContentMinSize:NSMakeSize(604., 288. + [o_titlebar_view frame].size.height)];
324         [o_detached_video_window setContentMinSize: NSMakeSize( 363., f_min_video_height + [o_detached_bottombar_view frame].size.height + [o_detached_titlebar_view frame].size.height )];
325     }
326     else if( b_video_deco )
327     {
328         [self setContentMinSize:NSMakeSize(604., 288.)];
329         [o_detached_video_window setContentMinSize: NSMakeSize( 363., f_min_video_height + [o_detached_bottombar_view frame].size.height )];
330     }
331     else
332     {   // !b_video_deco:
333         if (b_dark_interface)
334             [self setContentMinSize:NSMakeSize(604., 288. + [o_titlebar_view frame].size.height)];
335         else
336             [self setContentMinSize:NSMakeSize(604., 288.)];
337
338         [o_detached_bottombar_view setHidden:YES];
339         [o_detached_video_window setContentMinSize: NSMakeSize( f_min_video_height, f_min_video_height )];
340     }
341
342     [self setTitle: _NS("VLC media player")];
343     [o_time_fld setAlignment: NSCenterTextAlignment];
344     [o_time_fld setNeedsDisplay:YES];
345     b_dropzone_active = YES;
346     o_temp_view = [[NSView alloc] init];
347     [o_temp_view setAutoresizingMask:NSViewHeightSizable | NSViewWidthSizable];
348     [o_dropzone_view setFrame: [o_playlist_table frame]];
349     [o_left_split_view setFrame: [o_sidebar_view frame]];
350     if (b_nativeFullscreenMode)
351     {
352         NSRect frame;
353         [self setCollectionBehavior: NSWindowCollectionBehaviorFullScreenPrimary];
354         float f_width = [o_fullscreen_btn frame].size.width;
355
356         #define moveItem( item ) \
357         frame = [item frame]; \
358         frame.origin.x = f_width + frame.origin.x; \
359         [item setFrame: frame]
360
361         moveItem( o_effects_btn );
362         moveItem( o_volume_up_btn );
363         moveItem( o_volume_sld );
364         moveItem( o_volume_track_view );
365         moveItem( o_volume_down_btn );
366         moveItem( o_time_fld );
367         #undef moveItem
368
369         #define enlargeItem( item ) \
370         frame = [item frame]; \
371         frame.size.width = f_width + frame.size.width; \
372         [item setFrame: frame]
373
374         enlargeItem( o_time_sld );
375         enlargeItem( o_progress_bar );
376         enlargeItem( o_time_sld_background );
377         enlargeItem( o_time_sld_fancygradient_view );
378         #undef enlargeItem
379
380         [o_fullscreen_btn removeFromSuperviewWithoutNeedingDisplay];
381     }
382     else
383     {
384         [o_titlebar_view setFullscreenButtonHidden: YES];
385         if (b_video_deco)
386             [o_detached_titlebar_view setFullscreenButtonHidden: YES];
387     }
388
389     if (OSX_LION)
390     {
391         /* the default small size of the search field is slightly different on Lion, let's work-around that */
392         NSRect frame;
393         frame = [o_search_fld frame];
394         frame.origin.y = frame.origin.y + 2.0;
395         frame.size.height = frame.size.height - 1.0;
396         [o_search_fld setFrame: frame];
397     }
398
399     /* create the sidebar */
400     o_sidebaritems = [[NSMutableArray alloc] init];
401     SideBarItem *libraryItem = [SideBarItem itemWithTitle:_NS("LIBRARY") identifier:@"library"];
402     SideBarItem *playlistItem = [SideBarItem itemWithTitle:_NS("Playlist") identifier:@"playlist"];
403     [playlistItem setIcon: [NSImage imageNamed:@"sidebar-playlist"]];
404     SideBarItem *medialibraryItem = [SideBarItem itemWithTitle:_NS("Media Library") identifier:@"medialibrary"];
405     [medialibraryItem setIcon: [NSImage imageNamed:@"sidebar-playlist"]];
406     SideBarItem *mycompItem = [SideBarItem itemWithTitle:_NS("MY COMPUTER") identifier:@"mycomputer"];
407     SideBarItem *devicesItem = [SideBarItem itemWithTitle:_NS("DEVICES") identifier:@"devices"];
408     SideBarItem *lanItem = [SideBarItem itemWithTitle:_NS("LOCAL NETWORK") identifier:@"localnetwork"];
409     SideBarItem *internetItem = [SideBarItem itemWithTitle:_NS("INTERNET") identifier:@"internet"];
410
411     /* SD subnodes, inspired by the Qt4 intf */
412     char **ppsz_longnames;
413     int *p_categories;
414     char **ppsz_names = vlc_sd_GetNames( pl_Get( VLCIntf ), &ppsz_longnames, &p_categories );
415     if (!ppsz_names)
416         msg_Err( VLCIntf, "no sd item found" ); //TODO
417     char **ppsz_name = ppsz_names, **ppsz_longname = ppsz_longnames;
418     int *p_category = p_categories;
419     NSMutableArray *internetItems = [[NSMutableArray alloc] init];
420     NSMutableArray *devicesItems = [[NSMutableArray alloc] init];
421     NSMutableArray *lanItems = [[NSMutableArray alloc] init];
422     NSMutableArray *mycompItems = [[NSMutableArray alloc] init];
423     NSString *o_identifier;
424     for (; *ppsz_name; ppsz_name++, ppsz_longname++, p_category++)
425     {
426         o_identifier = [NSString stringWithCString: *ppsz_name encoding: NSUTF8StringEncoding];
427         switch (*p_category) {
428             case SD_CAT_INTERNET:
429                 {
430                     [internetItems addObject: [SideBarItem itemWithTitle: _NS(*ppsz_longname) identifier: o_identifier]];
431                     if (!strncmp( *ppsz_name, "podcast", 7 ))
432                         [internetItems removeLastObject]; // we don't support podcasts at this point (see #6017)
433 //                        [[internetItems lastObject] setIcon: [NSImage imageNamed:@"sidebar-podcast"]];
434                     else
435                         [[internetItems lastObject] setIcon: [NSImage imageNamed:@"NSApplicationIcon"]];
436                     [[internetItems lastObject] setSdtype: SD_CAT_INTERNET];
437                     [[internetItems lastObject] setUntranslatedTitle: [NSString stringWithUTF8String: *ppsz_longname]];
438                 }
439                 break;
440             case SD_CAT_DEVICES:
441                 {
442                     [devicesItems addObject: [SideBarItem itemWithTitle: _NS(*ppsz_longname) identifier: o_identifier]];
443                     [[devicesItems lastObject] setIcon: [NSImage imageNamed:@"NSApplicationIcon"]];
444                     [[devicesItems lastObject] setSdtype: SD_CAT_DEVICES];
445                     [[devicesItems lastObject] setUntranslatedTitle: [NSString stringWithUTF8String: *ppsz_longname]];
446                 }
447                 break;
448             case SD_CAT_LAN:
449                 {
450                     [lanItems addObject: [SideBarItem itemWithTitle: _NS(*ppsz_longname) identifier: o_identifier]];
451                     [[lanItems lastObject] setIcon: [NSImage imageNamed:@"sidebar-local"]];
452                     [[lanItems lastObject] setSdtype: SD_CAT_LAN];
453                     [[lanItems lastObject] setUntranslatedTitle: [NSString stringWithUTF8String: *ppsz_longname]];
454                 }
455                 break;
456             case SD_CAT_MYCOMPUTER:
457                 {
458                     [mycompItems addObject: [SideBarItem itemWithTitle: _NS(*ppsz_longname) identifier: o_identifier]];
459                     if (!strncmp( *ppsz_name, "video_dir", 9 ))
460                         [[mycompItems lastObject] setIcon: [NSImage imageNamed:@"sidebar-movie"]];
461                     else if (!strncmp( *ppsz_name, "audio_dir", 9 ))
462                         [[mycompItems lastObject] setIcon: [NSImage imageNamed:@"sidebar-music"]];
463                     else if (!strncmp( *ppsz_name, "picture_dir", 11 ))
464                         [[mycompItems lastObject] setIcon: [NSImage imageNamed:@"sidebar-pictures"]];
465                     else
466                         [[mycompItems lastObject] setIcon: [NSImage imageNamed:@"NSApplicationIcon"]];
467                     [[mycompItems lastObject] setUntranslatedTitle: [NSString stringWithUTF8String: *ppsz_longname]];
468                     [[mycompItems lastObject] setSdtype: SD_CAT_MYCOMPUTER];
469                 }
470                 break;
471             default:
472                 msg_Warn( VLCIntf, "unknown SD type found, skipping (%s)", *ppsz_name );
473                 break;
474         }
475
476         free( *ppsz_name );
477         free( *ppsz_longname );
478     }
479     [mycompItem setChildren: [NSArray arrayWithArray: mycompItems]];
480     [devicesItem setChildren: [NSArray arrayWithArray: devicesItems]];
481     [lanItem setChildren: [NSArray arrayWithArray: lanItems]];
482     [internetItem setChildren: [NSArray arrayWithArray: internetItems]];
483     [mycompItems release];
484     [devicesItems release];
485     [lanItems release];
486     [internetItems release];
487     free( ppsz_names );
488     free( ppsz_longnames );
489     free( p_categories );
490
491     [libraryItem setChildren: [NSArray arrayWithObjects: playlistItem, medialibraryItem, nil]];
492     [o_sidebaritems addObject: libraryItem];
493     if ([mycompItem hasChildren])
494         [o_sidebaritems addObject: mycompItem];
495     if ([devicesItem hasChildren])
496         [o_sidebaritems addObject: devicesItem];
497     if ([lanItem hasChildren])
498         [o_sidebaritems addObject: lanItem];
499     if ([internetItem hasChildren])
500         [o_sidebaritems addObject: internetItem];
501
502     [o_sidebar_view reloadData];
503     [o_sidebar_view selectRowIndexes:[NSIndexSet indexSetWithIndex:1] byExtendingSelection:NO];
504     [o_sidebar_view setDropItem:playlistItem dropChildIndex:NSOutlineViewDropOnItemIndex];
505     [o_sidebar_view registerForDraggedTypes:[NSArray arrayWithObjects: NSFilenamesPboardType, @"VLCPlaylistItemPboardType", nil]];
506
507     [o_sidebar_view setAutosaveName:@"mainwindow-sidebar"];
508     [(PXSourceList *)o_sidebar_view setDataSource:self];
509     [o_sidebar_view setDelegate:self];
510     [o_sidebar_view setAutosaveExpandedItems:YES];
511
512     [o_sidebar_view expandItem: libraryItem expandChildren: YES];
513
514     /* make sure we display the desired default appearance when VLC launches for the first time */
515     NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
516     if (![defaults objectForKey:@"VLCFirstRun"])
517     {
518         [defaults setObject:[NSDate date] forKey:@"VLCFirstRun"];
519
520         NSUInteger i_sidebaritem_count = [o_sidebaritems count];
521         for (NSUInteger x = 0; x < i_sidebaritem_count; x++)
522             [o_sidebar_view expandItem: [o_sidebaritems objectAtIndex: x] expandChildren: YES];
523     }
524
525     if( b_dark_interface )
526     {
527         [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(windowResizedOrMoved:) name: NSWindowDidResizeNotification object: nil];
528         [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(windowResizedOrMoved:) name: NSWindowDidMoveNotification object: nil];
529
530         [self setBackgroundColor: [NSColor clearColor]];
531         [self setOpaque: NO];
532         [self display];
533         [self setHasShadow:NO];
534         [self setHasShadow:YES];
535
536         NSRect winrect = [self frame];
537         CGFloat f_titleBarHeight = [o_titlebar_view frame].size.height;
538
539         [o_titlebar_view setFrame: NSMakeRect( 0, winrect.size.height - f_titleBarHeight,
540                                               winrect.size.width, f_titleBarHeight )];
541         [[self contentView] addSubview: o_titlebar_view positioned: NSWindowAbove relativeTo: o_split_view];
542
543         if (winrect.size.height > 100)
544         {
545             [self setFrame: winrect display:YES animate:YES];
546             previousSavedFrame = winrect;
547         }
548
549         winrect = [o_split_view frame];
550         winrect.size.height = winrect.size.height - f_titleBarHeight;
551         [o_split_view setFrame: winrect];
552         [o_video_view setFrame: winrect];
553
554         /* detached video window */
555         winrect = [o_detached_video_window frame];
556         if (b_video_deco)
557         {
558             [o_detached_titlebar_view setFrame: NSMakeRect( 0, winrect.size.height - f_titleBarHeight, winrect.size.width, f_titleBarHeight )];
559             [[o_detached_video_window contentView] addSubview: o_detached_titlebar_view positioned: NSWindowAbove relativeTo: nil];
560         }
561
562         o_color_backdrop = [[VLCColorView alloc] initWithFrame: [o_split_view frame]];
563         [[self contentView] addSubview: o_color_backdrop positioned: NSWindowBelow relativeTo: o_split_view];
564         [o_color_backdrop setAutoresizingMask:NSViewHeightSizable | NSViewWidthSizable];
565     }
566     else
567     {
568         NSRect frame;
569         frame = [o_time_sld_fancygradient_view frame];
570         frame.size.height = frame.size.height - 1;
571         frame.origin.y = frame.origin.y + 1;
572         [o_time_sld_fancygradient_view setFrame: frame];
573
574         frame = [o_detached_time_sld_fancygradient_view frame];
575         frame.size.height = frame.size.height - 1;
576         frame.origin.y = frame.origin.y + 1;
577         [o_detached_time_sld_fancygradient_view setFrame: frame];
578
579         [o_video_view setFrame: [o_split_view frame]];
580         [o_playlist_table setBorderType: NSNoBorder];
581         [o_sidebar_scrollview setBorderType: NSNoBorder];
582     }
583
584     NSRect frame;
585     frame = [o_time_sld_fancygradient_view frame];
586     frame.size.width = 0;
587     [o_time_sld_fancygradient_view setFrame: frame];
588
589     frame = [o_detached_time_sld_fancygradient_view frame];
590     frame.size.width = 0;
591     [o_detached_time_sld_fancygradient_view setFrame: frame];
592
593     if (OSX_LION)
594     {
595         [o_resize_view setImage: NULL];
596         [o_detached_resize_view setImage: NULL];
597     }
598
599     if ([self styleMask] & NSResizableWindowMask)
600     {
601         [o_resize_view removeFromSuperviewWithoutNeedingDisplay];
602         [o_detached_resize_view removeFromSuperviewWithoutNeedingDisplay];
603     }
604
605     [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(someWindowWillClose:) name: NSWindowWillCloseNotification object: nil];
606     [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(someWindowWillMiniaturize:) name: NSWindowWillMiniaturizeNotification object:nil];
607     [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(applicationWillTerminate:) name: NSApplicationWillTerminateNotification object: nil];
608     [[VLCMain sharedInstance] playbackModeUpdated];
609
610     [o_split_view setAutosaveName:@"10thanniversary-splitview"];
611     if (b_splitviewShouldBeHidden)
612     {
613         [self hideSplitView];
614         i_lastSplitViewHeight = 300;
615     }
616 }
617
618 #pragma mark -
619 #pragma mark interface customization
620 - (void)toggleJumpButtons
621 {
622     b_show_jump_buttons = config_GetInt( VLCIntf, "macosx-show-playback-buttons" );
623
624     if (b_show_jump_buttons)
625         [self addJumpButtons];
626     else
627         [self removeJumpButtons];
628 }
629
630 - (void)addJumpButtons
631 {
632     NSRect preliminaryFrame = [o_bwd_btn frame];
633     BOOL b_enabled = [o_bwd_btn isEnabled];
634     preliminaryFrame.size.width = 26.;
635     o_prev_btn = [[NSButton alloc] initWithFrame:preliminaryFrame];
636     [o_prev_btn setButtonType: NSMomentaryChangeButton];
637     [o_prev_btn setImage: [NSImage imageNamed:@"back-single"]];
638     [o_prev_btn setAlternateImage: [NSImage imageNamed:@"back-pressed-single"]];
639     [o_prev_btn setBezelStyle:NSRegularSquareBezelStyle];
640     [o_prev_btn setBordered:NO];
641     [o_prev_btn setTarget:self];
642     [o_prev_btn setAction:@selector(prev:)];
643     [o_prev_btn setToolTip: _NS("Previous")];
644     [o_prev_btn setEnabled: b_enabled];
645
646     o_next_btn = [[NSButton alloc] initWithFrame:preliminaryFrame];
647     [o_next_btn setButtonType: NSMomentaryChangeButton];
648     [o_next_btn setImage: [NSImage imageNamed:@"forward-single"]];
649     [o_next_btn setAlternateImage: [NSImage imageNamed:@"forward-pressed-single"]];
650     [o_next_btn setBezelStyle:NSRegularSquareBezelStyle];
651     [o_next_btn setBordered:NO];
652     [o_next_btn setTarget:self];
653     [o_next_btn setAction:@selector(next:)];
654     [o_next_btn setToolTip: _NS("Next")];
655     [o_next_btn setEnabled: b_enabled];
656
657     NSRect frame;
658     float f_space = 32.;
659     #define moveItem( item ) \
660     frame = [item frame]; \
661     frame.origin.x = frame.origin.x + f_space; \
662     [[item animator] setFrame: frame]
663
664     moveItem( o_bwd_btn );
665     moveItem( o_play_btn );
666     moveItem( o_fwd_btn );
667     f_space = 62.;
668     moveItem( o_stop_btn );
669     moveItem( o_playlist_btn );
670     moveItem( o_repeat_btn );
671     moveItem( o_shuffle_btn );
672     #undef moveItem
673
674     #define resizeItem( item ) \
675     frame = [item frame]; \
676     frame.size.width = frame.size.width - f_space; \
677     frame.origin.x = frame.origin.x + f_space; \
678     [[item animator] setFrame: frame]
679
680     resizeItem( o_time_sld );
681     resizeItem( o_progress_bar );
682     resizeItem( o_time_sld_background );
683     resizeItem( o_time_sld_fancygradient_view );
684     #undef resizeItem
685
686     preliminaryFrame.origin.x = [o_next_btn frame].origin.x + 80. + [o_fwd_btn frame].size.width;
687     [o_next_btn setFrame: preliminaryFrame];
688
689     // wait until the animation is done
690     [[self contentView] performSelector:@selector(addSubview:) withObject:o_prev_btn afterDelay:.2];
691     [[self contentView] performSelector:@selector(addSubview:) withObject:o_next_btn afterDelay:.2];
692
693     [o_fwd_btn setAction:@selector(forward:)];
694     [o_bwd_btn setAction:@selector(backward:)];
695 }
696
697 - (void)removeJumpButtons
698 {
699     if (!o_prev_btn || !o_next_btn )
700         return;
701
702     [[o_prev_btn animator] setHidden: YES];
703     [[o_next_btn animator] setHidden: YES];
704     [o_prev_btn removeFromSuperviewWithoutNeedingDisplay];
705     [o_next_btn removeFromSuperviewWithoutNeedingDisplay];
706     [o_prev_btn release];
707     [o_next_btn release];
708
709     NSRect frame;
710     float f_space = 32.;
711     #define moveItem( item ) \
712     frame = [item frame]; \
713     frame.origin.x = frame.origin.x - f_space; \
714     [[item animator] setFrame: frame]
715
716     moveItem( o_bwd_btn );
717     moveItem( o_play_btn );
718     moveItem( o_fwd_btn );
719     f_space = 62.;
720     moveItem( o_stop_btn );
721     moveItem( o_playlist_btn );
722     moveItem( o_repeat_btn );
723     moveItem( o_shuffle_btn );
724     #undef moveItem
725
726     #define resizeItem( item ) \
727     frame = [item frame]; \
728     frame.size.width = frame.size.width + f_space; \
729     frame.origin.x = frame.origin.x - f_space; \
730     [[item animator] setFrame: frame]
731
732     resizeItem( o_time_sld );
733     resizeItem( o_progress_bar );
734     resizeItem( o_time_sld_background );
735     resizeItem( o_time_sld_fancygradient_view );
736     #undef resizeItem
737
738     [o_bottombar_view setNeedsDisplay:YES];
739
740     [o_fwd_btn setAction:@selector(fwd:)];
741     [o_bwd_btn setAction:@selector(bwd:)];
742 }
743
744 - (void)togglePlaymodeButtons
745 {
746     b_show_playmode_buttons = config_GetInt( VLCIntf, "macosx-show-playmode-buttons" );
747
748     if (b_show_playmode_buttons)
749         [self addPlaymodeButtons];
750     else
751         [self removePlaymodeButtons];
752 }
753
754 - (void)addPlaymodeButtons
755 {
756     NSRect frame;
757     float f_space = [o_repeat_btn frame].size.width + [o_shuffle_btn frame].size.width - 6.;
758
759     // FIXME: switch o_playlist_btn artwork
760
761     #define resizeItem( item ) \
762     frame = [item frame]; \
763     frame.size.width = frame.size.width - f_space; \
764     frame.origin.x = frame.origin.x + f_space; \
765     [[item animator] setFrame: frame]
766
767     resizeItem( o_time_sld );
768     resizeItem( o_progress_bar );
769     resizeItem( o_time_sld_background );
770     resizeItem( o_time_sld_fancygradient_view );
771     #undef resizeItem
772
773     [[o_repeat_btn animator] setHidden: NO];
774     [[o_shuffle_btn animator] setHidden: NO];
775 }
776
777 - (void)removePlaymodeButtons
778 {
779     NSRect frame;
780     float f_space = [o_repeat_btn frame].size.width + [o_shuffle_btn frame].size.width - 6.;
781     [o_repeat_btn setHidden: YES];
782     [o_shuffle_btn setHidden: YES];
783
784     // FIXME: switch o_playlist_btn artwork
785
786     #define resizeItem( item ) \
787     frame = [item frame]; \
788     frame.size.width = frame.size.width + f_space; \
789     frame.origin.x = frame.origin.x - f_space; \
790     [[item animator] setFrame: frame]
791
792     resizeItem( o_time_sld );
793     resizeItem( o_progress_bar );
794     resizeItem( o_time_sld_background );
795     resizeItem( o_time_sld_fancygradient_view );
796     #undef resizeItem
797 }
798
799 #pragma mark -
800 #pragma mark Button Actions
801
802 - (IBAction)play:(id)sender
803 {
804     [[VLCCoreInteraction sharedInstance] play];
805 }
806
807 - (void)resetPreviousButton
808 {
809     if (([NSDate timeIntervalSinceReferenceDate] - last_bwd_event) >= 0.35) {
810         // seems like no further event occurred, so let's switch the playback item
811         [[VLCCoreInteraction sharedInstance] previous];
812         just_triggered_previous = NO;
813     }
814 }
815
816 - (void)resetBackwardSkip
817 {
818     // the user stopped skipping, so let's allow him to change the item
819     if (([NSDate timeIntervalSinceReferenceDate] - last_bwd_event) >= 0.35)
820         just_triggered_previous = NO;
821 }
822
823 - (IBAction)prev:(id)sender
824 {
825     [[VLCCoreInteraction sharedInstance] previous];
826 }
827
828 - (IBAction)bwd:(id)sender
829 {
830     if(!just_triggered_previous)
831     {
832         just_triggered_previous = YES;
833         [self performSelector:@selector(resetPreviousButton)
834                    withObject: NULL
835                    afterDelay:0.40];
836     }
837     else
838     {
839         if (([NSDate timeIntervalSinceReferenceDate] - last_fwd_event) > 0.16 )
840         {
841             // we just skipped 4 "continous" events, otherwise we are too fast
842             [[VLCCoreInteraction sharedInstance] backwardExtraShort];
843             last_bwd_event = [NSDate timeIntervalSinceReferenceDate];
844             [self performSelector:@selector(resetBackwardSkip)
845                        withObject: NULL
846                        afterDelay:0.40];
847         }
848     }
849 }
850
851 - (IBAction)backward:(id)sender
852 {
853     [[VLCCoreInteraction sharedInstance] backwardShort];
854 }
855
856 - (void)resetNextButton
857 {
858     if (([NSDate timeIntervalSinceReferenceDate] - last_fwd_event) >= 0.35) {
859         // seems like no further event occurred, so let's switch the playback item
860         [[VLCCoreInteraction sharedInstance] next];
861         just_triggered_next = NO;
862     }
863 }
864
865 - (void)resetForwardSkip
866 {
867     // the user stopped skipping, so let's allow him to change the item
868     if (([NSDate timeIntervalSinceReferenceDate] - last_fwd_event) >= 0.35)
869         just_triggered_next = NO;
870 }
871
872 - (IBAction)next:(id)sender
873 {
874     [[VLCCoreInteraction sharedInstance] next];
875 }
876
877 - (IBAction)forward:(id)sender
878 {
879     [[VLCCoreInteraction sharedInstance] forwardShort];
880 }
881
882 - (IBAction)fwd:(id)sender
883 {
884    if(!just_triggered_next)
885     {
886         just_triggered_next = YES;
887         [self performSelector:@selector(resetNextButton)
888                    withObject: NULL
889                    afterDelay:0.40];
890     }
891     else
892     {
893         if (([NSDate timeIntervalSinceReferenceDate] - last_fwd_event) > 0.16 )
894         {
895             // we just skipped 4 "continous" events, otherwise we are too fast
896             [[VLCCoreInteraction sharedInstance] forwardExtraShort];
897             last_fwd_event = [NSDate timeIntervalSinceReferenceDate];
898             [self performSelector:@selector(resetForwardSkip)
899                        withObject: NULL
900                        afterDelay:0.40];
901         }
902     }
903 }
904
905 - (IBAction)stop:(id)sender
906 {
907     [[VLCCoreInteraction sharedInstance] stop];
908 }
909
910 - (void)resizePlaylistAfterCollapse
911 {
912     NSRect plrect;
913     plrect = [[o_playlist_table animator] frame];
914     plrect.size.height = i_lastSplitViewHeight - 19.0; // actual pl top bar height, which differs from its frame
915     [[o_playlist_table animator] setFrame: plrect];
916
917     NSRect rightSplitRect;
918     rightSplitRect = [o_right_split_view frame];
919     plrect = [[o_dropzone_box animator] frame];
920     plrect.origin.x = (rightSplitRect.size.width - plrect.size.width) / 2;
921     plrect.origin.y = (rightSplitRect.size.height - plrect.size.height) / 2;
922     [[o_dropzone_box animator] setFrame: plrect];
923 }
924
925 - (void)makeSplitViewVisible
926 {
927     if( b_dark_interface )
928         [self setContentMinSize: NSMakeSize( 604., 288. + [o_titlebar_view frame].size.height )];
929     else
930         [self setContentMinSize: NSMakeSize( 604., 288. )];
931
932     NSRect old_frame = [self frame];
933     float newHeight = [self minSize].height;
934     if( old_frame.size.height < newHeight )
935     {
936         NSRect new_frame = old_frame;
937         new_frame.origin.y = old_frame.origin.y + old_frame.size.height - newHeight;
938         new_frame.size.height = newHeight;
939
940         [[self animator] setFrame: new_frame display: YES animate: YES];
941     }
942
943     [o_video_view setHidden: YES];
944     [o_split_view setHidden: NO];
945     [self makeFirstResponder: nil];
946
947 }
948
949 - (void)makeSplitViewHidden
950 {
951     if( b_dark_interface )
952         [self setContentMinSize: NSMakeSize( 604., f_min_video_height + [o_titlebar_view frame].size.height )];
953     else
954         [self setContentMinSize: NSMakeSize( 604., f_min_video_height )];
955
956     [o_split_view setHidden: YES];
957     [o_video_view setHidden: NO];
958
959     if( [[o_video_view subviews] count] > 0 )
960         [self makeFirstResponder: [[o_video_view subviews] objectAtIndex:0]];
961 }
962
963 - (IBAction)togglePlaylist:(id)sender
964 {
965     if (![self isVisible] && sender != nil)
966     {
967         [self makeKeyAndOrderFront: sender];
968         return;
969     }
970
971     BOOL b_activeVideo = [[VLCMain sharedInstance] activeVideoPlayback];
972     BOOL b_restored = NO;
973
974     // TODO: implement toggle playlist in this situation (triggerd via menu item).
975     // but for now we block this case, to avoid displaying only the half
976     if( b_nativeFullscreenMode && b_fullscreen && b_activeVideo && sender != nil )
977         return;
978
979     if (b_dropzone_active && ([[NSApp currentEvent] modifierFlags] & NSAlternateKeyMask) != 0)
980     {
981         [self hideDropZone];
982         return;
983     }
984
985     if ( !(b_nativeFullscreenMode && b_fullscreen) && !b_splitview_removed && ( (([[NSApp currentEvent] modifierFlags] & NSAlternateKeyMask) != 0 && b_activeVideo)
986                                   || (b_nonembedded && sender != nil)
987                                   || (!b_activeVideo && sender != nil)
988                                   || b_minimized_view ) )
989     {
990         [self hideSplitView];
991     }
992     else
993     {
994         if (b_splitview_removed)
995         {
996             if( !b_nonembedded || ( sender != nil && b_nonembedded))
997                 [self showSplitView];
998
999             if (sender == nil)
1000                 b_minimized_view = YES;
1001             else
1002                 b_minimized_view = NO;
1003
1004             if (b_activeVideo)
1005                 b_restored = YES;
1006         }
1007
1008         if (!b_nonembedded)
1009         {
1010             if (([o_video_view isHidden] && b_activeVideo) || b_restored || (b_activeVideo && sender == nil) )
1011                 [self makeSplitViewHidden];
1012             else
1013                 [self makeSplitViewVisible];
1014         }
1015         else
1016         {
1017             [o_split_view setHidden: NO];
1018             [o_playlist_table setHidden: NO];
1019             [o_video_view setHidden: !b_activeVideo];
1020             if( b_activeVideo && [[o_video_view subviews] count] > 0 )
1021                 [o_detached_video_window makeFirstResponder: [[o_video_view subviews] objectAtIndex:0]];
1022         }
1023     }
1024 }
1025
1026 - (void)setRepeatOne
1027 {
1028     [o_repeat_btn setImage: o_repeat_one_img];
1029     [o_repeat_btn setAlternateImage: o_repeat_one_pressed_img];
1030 }
1031
1032 - (void)setRepeatAll
1033 {
1034     [o_repeat_btn setImage: o_repeat_all_img];
1035     [o_repeat_btn setAlternateImage: o_repeat_all_pressed_img];
1036 }
1037
1038 - (void)setRepeatOff
1039 {
1040     [o_repeat_btn setImage: o_repeat_img];
1041     [o_repeat_btn setAlternateImage: o_repeat_pressed_img];
1042 }
1043
1044 - (IBAction)repeat:(id)sender
1045 {
1046     vlc_value_t looping,repeating;
1047     intf_thread_t * p_intf = VLCIntf;
1048     playlist_t * p_playlist = pl_Get( p_intf );
1049
1050     var_Get( p_playlist, "repeat", &repeating );
1051     var_Get( p_playlist, "loop", &looping );
1052
1053     if( !repeating.b_bool && !looping.b_bool )
1054     {
1055         /* was: no repeating at all, switching to Repeat One */
1056         [[VLCCoreInteraction sharedInstance] repeatOne];
1057         [self setRepeatOne];
1058     }
1059     else if( repeating.b_bool && !looping.b_bool )
1060     {
1061         /* was: Repeat One, switching to Repeat All */
1062         [[VLCCoreInteraction sharedInstance] repeatAll];
1063         [self setRepeatAll];
1064     }
1065     else
1066     {
1067         /* was: Repeat All or bug in VLC, switching to Repeat Off */
1068         [[VLCCoreInteraction sharedInstance] repeatOff];
1069         [self setRepeatOff];
1070     }
1071 }
1072
1073 - (void)setShuffle
1074 {
1075     bool b_value;
1076     playlist_t *p_playlist = pl_Get( VLCIntf );
1077     b_value = var_GetBool( p_playlist, "random" );
1078
1079     if(b_value) {
1080         [o_shuffle_btn setImage: o_shuffle_on_img];
1081         [o_shuffle_btn setAlternateImage: o_shuffle_on_pressed_img];
1082     }
1083     else
1084     {
1085         [o_shuffle_btn setImage: o_shuffle_img];
1086         [o_shuffle_btn setAlternateImage: o_shuffle_pressed_img];
1087     }
1088 }
1089
1090 - (IBAction)shuffle:(id)sender
1091 {
1092     [[VLCCoreInteraction sharedInstance] shuffle];
1093     [self setShuffle];
1094 }
1095
1096 - (IBAction)timeSliderAction:(id)sender
1097 {
1098     float f_updated;
1099     input_thread_t * p_input;
1100
1101     switch( [[NSApp currentEvent] type] )
1102     {
1103         case NSLeftMouseUp:
1104         case NSLeftMouseDown:
1105         case NSLeftMouseDragged:
1106             f_updated = [sender floatValue];
1107             break;
1108
1109         default:
1110             return;
1111     }
1112     p_input = pl_CurrentInput( VLCIntf );
1113     if( p_input != NULL )
1114     {
1115         vlc_value_t pos;
1116         NSString * o_time;
1117
1118         pos.f_float = f_updated / 10000.;
1119         var_Set( p_input, "position", pos );
1120         [o_time_sld setFloatValue: f_updated];
1121
1122         o_time = [self getCurrentTimeAsString: p_input];
1123         [o_time_fld setStringValue: o_time];
1124         [o_fspanel setStreamPos: f_updated andTime: o_time];
1125         vlc_object_release( p_input );
1126     }
1127 }
1128
1129 - (IBAction)volumeAction:(id)sender
1130 {
1131     if (sender == o_volume_sld)
1132         [[VLCCoreInteraction sharedInstance] setVolume: [sender intValue]];
1133     else if (sender == o_volume_down_btn)
1134     {
1135         [[VLCCoreInteraction sharedInstance] mute];
1136     }
1137     else
1138         [[VLCCoreInteraction sharedInstance] setVolume: AOUT_VOLUME_MAX];
1139 }
1140
1141 - (IBAction)effects:(id)sender
1142 {
1143     [[VLCMainMenu sharedInstance] showAudioEffects: sender];
1144 }
1145
1146 - (IBAction)fullscreen:(id)sender
1147 {
1148     [[VLCCoreInteraction sharedInstance] toggleFullscreen];
1149 }
1150
1151 - (IBAction)dropzoneButtonAction:(id)sender
1152 {
1153     [[[VLCMain sharedInstance] open] openFileGeneric];
1154 }
1155
1156 #pragma mark -
1157 #pragma mark overwritten default functionality
1158 - (BOOL)canBecomeKeyWindow
1159 {
1160     return YES;
1161 }
1162
1163 - (BOOL)validateMenuItem:(NSMenuItem *)menuItem
1164 {
1165     SEL s_menuAction = [menuItem action];
1166
1167     if ((s_menuAction == @selector(performClose:)) || (s_menuAction == @selector(performMiniaturize:)) || (s_menuAction == @selector(performZoom:)))
1168             return YES;
1169
1170     return [super validateMenuItem:menuItem];
1171 }
1172
1173 - (void)setTitle:(NSString *)title
1174 {
1175     if (b_dark_interface)
1176     {
1177         [o_titlebar_view setWindowTitle: title];
1178         if (b_video_deco)
1179             [o_detached_titlebar_view setWindowTitle: title];
1180     }
1181     if (b_nonembedded && [[VLCMain sharedInstance] activeVideoPlayback])
1182         [o_detached_video_window setTitle: title];
1183     [super setTitle: title];
1184 }
1185
1186 - (void)performClose:(id)sender
1187 {
1188     NSWindow *o_key_window = [NSApp keyWindow];
1189
1190     if (b_dark_interface || !b_video_deco)
1191     {
1192         [o_key_window orderOut: sender];
1193         if ( [[VLCMain sharedInstance] activeVideoPlayback] && ( !b_nonembedded || o_key_window != self ))
1194             [[VLCCoreInteraction sharedInstance] stop];
1195     }
1196     else
1197     {
1198         if( b_nonembedded && o_key_window != self )
1199             [o_detached_video_window performClose: sender];
1200         else
1201             [super performClose: sender];
1202     }
1203 }
1204
1205 - (void)performMiniaturize:(id)sender
1206 {
1207     if (b_dark_interface)
1208         [self miniaturize: sender];
1209     else
1210         [super performMiniaturize: sender];
1211 }
1212
1213 - (void)performZoom:(id)sender
1214 {
1215     if (b_dark_interface)
1216         [self customZoom: sender];
1217     else
1218         [super performZoom: sender];
1219 }
1220
1221 - (void)zoom:(id)sender
1222 {
1223     if (b_dark_interface)
1224         [self customZoom: sender];
1225     else
1226         [super zoom: sender];
1227 }
1228
1229 /**
1230  * Given a proposed frame rectangle, return a modified version
1231  * which will fit inside the screen.
1232  *
1233  * This method is based upon NSWindow.m, part of the GNUstep GUI Library, licensed under LGPLv2+.
1234  *    Authors:  Scott Christley <scottc@net-community.com>, Venkat Ajjanagadde <venkat@ocbi.com>,
1235  *              Felipe A. Rodriguez <far@ix.netcom.com>, Richard Frith-Macdonald <richard@brainstorm.co.uk>
1236  *    Copyright (C) 1996 Free Software Foundation, Inc.
1237  */
1238 - (NSRect) customConstrainFrameRect: (NSRect)frameRect toScreen: (NSScreen*)screen
1239 {
1240     NSRect screenRect = [screen visibleFrame];
1241     float difference;
1242
1243     /* Move top edge of the window inside the screen */
1244     difference = NSMaxY (frameRect) - NSMaxY (screenRect);
1245     if (difference > 0)
1246     {
1247         frameRect.origin.y -= difference;
1248     }
1249
1250     /* If the window is resizable, resize it (if needed) so that the
1251      bottom edge is on the screen or can be on the screen when the user moves
1252      the window */
1253     difference = NSMaxY (screenRect) - NSMaxY (frameRect);
1254     if (_styleMask & NSResizableWindowMask)
1255     {
1256         float difference2;
1257
1258         difference2 = screenRect.origin.y - frameRect.origin.y;
1259         difference2 -= difference;
1260         // Take in account the space between the top of window and the top of the
1261         // screen which can be used to move the bottom of the window on the screen
1262         if (difference2 > 0)
1263         {
1264             frameRect.size.height -= difference2;
1265             frameRect.origin.y += difference2;
1266         }
1267
1268         /* Ensure that resizing doesn't makewindow smaller than minimum */
1269         difference2 = [self minSize].height - frameRect.size.height;
1270         if (difference2 > 0)
1271         {
1272             frameRect.size.height += difference2;
1273             frameRect.origin.y -= difference2;
1274         }
1275     }
1276
1277     return frameRect;
1278 }
1279
1280 #define DIST 3
1281
1282 /**
1283  Zooms the receiver.   This method calls the delegate method
1284  windowShouldZoom:toFrame: to determine if the window should
1285  be allowed to zoom to full screen.
1286  *
1287  * This method is based upon NSWindow.m, part of the GNUstep GUI Library, licensed under LGPLv2+.
1288  *    Authors:  Scott Christley <scottc@net-community.com>, Venkat Ajjanagadde <venkat@ocbi.com>,
1289  *              Felipe A. Rodriguez <far@ix.netcom.com>, Richard Frith-Macdonald <richard@brainstorm.co.uk>
1290  *    Copyright (C) 1996 Free Software Foundation, Inc.
1291  */
1292 - (void)customZoom:(id)sender
1293 {
1294     NSRect maxRect = [[self screen] visibleFrame];
1295     NSRect currentFrame = [self frame];
1296
1297     if ([[self delegate] respondsToSelector: @selector(windowWillUseStandardFrame:defaultFrame:)])
1298     {
1299         maxRect = [[self delegate] windowWillUseStandardFrame: self defaultFrame: maxRect];
1300     }
1301
1302     maxRect = [self customConstrainFrameRect: maxRect toScreen: [self screen]];
1303
1304     // Compare the new frame with the current one
1305     if ((abs(NSMaxX(maxRect) - NSMaxX(currentFrame)) < DIST)
1306         && (abs(NSMaxY(maxRect) - NSMaxY(currentFrame)) < DIST)
1307         && (abs(NSMinX(maxRect) - NSMinX(currentFrame)) < DIST)
1308         && (abs(NSMinY(maxRect) - NSMinY(currentFrame)) < DIST))
1309     {
1310         // Already in zoomed mode, reset user frame, if stored
1311         if ([self frameAutosaveName] != nil)
1312         {
1313             [self setFrame: previousSavedFrame display: YES animate: YES];
1314             [self saveFrameUsingName: [self frameAutosaveName]];
1315         }
1316         return;
1317     }
1318
1319     if ([self frameAutosaveName] != nil)
1320     {
1321         [self saveFrameUsingName: [self frameAutosaveName]];
1322         previousSavedFrame = [self frame];
1323     }
1324
1325     [self setFrame: maxRect display: YES animate: YES];
1326 }
1327
1328 - (void)windowResizedOrMoved:(NSNotification *)notification
1329 {
1330     [self saveFrameUsingName: [self frameAutosaveName]];
1331 }
1332
1333 - (void)applicationWillTerminate:(NSNotification *)notification
1334 {
1335     [self saveFrameUsingName: [self frameAutosaveName]];
1336 }
1337
1338 - (void)someWindowWillClose:(NSNotification *)notification
1339 {
1340     if([notification object] == o_detached_video_window || ([notification object] == self && !b_nonembedded))
1341     {
1342         if ([[VLCMain sharedInstance] activeVideoPlayback])
1343             [[VLCCoreInteraction sharedInstance] stop];
1344     }
1345 }
1346
1347 - (void)someWindowWillMiniaturize:(NSNotification *)notification
1348 {
1349     if (config_GetInt( VLCIntf, "macosx-pause-minimized" ))
1350     {
1351         if([notification object] == o_detached_video_window || ([notification object] == self && !b_nonembedded))
1352         {
1353             if([[VLCMain sharedInstance] activeVideoPlayback])
1354                 [[VLCCoreInteraction sharedInstance] pause];
1355         }
1356     }
1357 }
1358
1359 - (NSSize)windowWillResize:(NSWindow *)window toSize:(NSSize)proposedFrameSize
1360 {
1361     id videoWindow = [o_video_view window];
1362     if (![[VLCMain sharedInstance] activeVideoPlayback] || nativeVideoSize.width == 0. || nativeVideoSize.height == 0. || window != videoWindow)
1363         return proposedFrameSize;
1364
1365     // needed when entering lion fullscreen mode
1366     if( b_fullscreen )
1367         return proposedFrameSize;
1368
1369     if( [[VLCCoreInteraction sharedInstance] aspectRatioIsLocked] )
1370     {
1371         NSRect videoWindowFrame = [videoWindow frame];
1372         NSRect viewRect = [o_video_view convertRect:[o_video_view bounds] toView: nil];
1373         NSRect contentRect = [videoWindow contentRectForFrameRect:videoWindowFrame];
1374         float marginy = viewRect.origin.y + videoWindowFrame.size.height - contentRect.size.height;
1375         float marginx = contentRect.size.width - viewRect.size.width;
1376         if( b_dark_interface && b_video_deco )
1377             marginy += [o_titlebar_view frame].size.height;
1378
1379         proposedFrameSize.height = (proposedFrameSize.width - marginx) * nativeVideoSize.height / nativeVideoSize.width + marginy;
1380     }
1381
1382     return proposedFrameSize;
1383 }
1384
1385 #pragma mark -
1386 #pragma mark Update interface and respond to foreign events
1387 - (void)showDropZone
1388 {
1389     b_dropzone_active = YES;
1390     [o_right_split_view addSubview: o_dropzone_view];
1391     [o_dropzone_view setFrame: [o_playlist_table frame]];
1392     [[o_playlist_table animator] setHidden:YES];
1393 }
1394
1395 - (void)hideDropZone
1396 {
1397     b_dropzone_active = NO;
1398     [o_dropzone_view removeFromSuperview];
1399     [[o_playlist_table animator] setHidden: NO];
1400 }
1401
1402 - (void)hideSplitView
1403 {
1404     NSRect winrect = [self frame];
1405     i_lastSplitViewHeight = [o_split_view frame].size.height;
1406     winrect.size.height = winrect.size.height - i_lastSplitViewHeight;
1407     winrect.origin.y = winrect.origin.y + i_lastSplitViewHeight;
1408     [self setFrame: winrect display: YES animate: YES];
1409     [self performSelector:@selector(hideDropZone) withObject:nil afterDelay:0.1];
1410     if (b_dark_interface)
1411     {
1412         [self setContentMinSize: NSMakeSize( 604., [o_bottombar_view frame].size.height + [o_titlebar_view frame].size.height )];
1413         [self setContentMaxSize: NSMakeSize( FLT_MAX, [o_bottombar_view frame].size.height + [o_titlebar_view frame].size.height )];
1414     }
1415     else
1416     {
1417         [self setContentMinSize: NSMakeSize( 604., [o_bottombar_view frame].size.height )];
1418         [self setContentMaxSize: NSMakeSize( FLT_MAX, [o_bottombar_view frame].size.height )];
1419     }
1420
1421     b_splitview_removed = YES;
1422 }
1423
1424 - (void)showSplitView
1425 {
1426     [self updateWindow];
1427     if (b_dark_interface)
1428         [self setContentMinSize:NSMakeSize( 604., 288. + [o_titlebar_view frame].size.height )];
1429     else
1430         [self setContentMinSize:NSMakeSize( 604., 288. )];
1431     [self setContentMaxSize: NSMakeSize( FLT_MAX, FLT_MAX )];
1432
1433     NSRect winrect;
1434     winrect = [self frame];
1435     winrect.size.height = winrect.size.height + i_lastSplitViewHeight;
1436     winrect.origin.y = winrect.origin.y - i_lastSplitViewHeight;
1437     [self setFrame: winrect display: YES animate: YES];
1438
1439     [self performSelector:@selector(resizePlaylistAfterCollapse) withObject: nil afterDelay:0.75];
1440
1441     b_splitview_removed = NO;
1442 }
1443
1444 - (NSString *)getCurrentTimeAsString:(input_thread_t *)p_input
1445 {
1446     assert( p_input != nil );
1447
1448     vlc_value_t time;
1449     char psz_time[MSTRTIME_MAX_SIZE];
1450
1451     var_Get( p_input, "time", &time );
1452
1453     mtime_t dur = input_item_GetDuration( input_GetItem( p_input ) );
1454     if( [o_time_fld timeRemaining] && dur > 0 )
1455     {
1456         mtime_t remaining = 0;
1457         if( dur > time.i_time )
1458             remaining = dur - time.i_time;
1459         return [NSString stringWithFormat: @"-%s", secstotimestr( psz_time, ( remaining / 1000000 ) )];
1460     }
1461     else
1462         return [NSString stringWithUTF8String: secstotimestr( psz_time, ( time.i_time / 1000000 ) )];
1463 }
1464
1465 - (void)updateTimeSlider
1466 {
1467     input_thread_t * p_input;
1468     p_input = pl_CurrentInput( VLCIntf );
1469     if( p_input )
1470     {
1471         NSString * o_time;
1472         vlc_value_t pos;
1473         float f_updated;
1474
1475         var_Get( p_input, "position", &pos );
1476         f_updated = 10000. * pos.f_float;
1477         [o_time_sld setFloatValue: f_updated];
1478
1479         o_time = [self getCurrentTimeAsString: p_input];
1480
1481         mtime_t dur = input_item_GetDuration( input_GetItem( p_input ) );
1482         if (dur == -1) {
1483             [o_time_sld setEnabled: NO];
1484             [o_time_sld setHidden: YES];
1485             [o_time_sld_fancygradient_view setHidden: YES];
1486         } else {
1487             [o_time_sld setEnabled: YES];
1488             [o_time_sld setHidden: NO];
1489             [o_time_sld_fancygradient_view setHidden: NO];
1490         }
1491
1492         [o_time_fld setStringValue: o_time];
1493         [o_time_fld setNeedsDisplay:YES];
1494         [o_fspanel setStreamPos: f_updated andTime: o_time];
1495         vlc_object_release( p_input );
1496     }
1497     else
1498     {
1499         [o_time_sld setFloatValue: 0.0];
1500         [o_time_fld setStringValue: @"00:00"];
1501         [o_time_sld setEnabled: NO];
1502         [o_time_sld setHidden: YES];
1503         [o_time_sld_fancygradient_view setHidden: YES];
1504         if (b_video_deco)
1505             [o_detached_time_sld_fancygradient_view setHidden: YES];
1506     }
1507
1508     if (b_video_deco)
1509     {
1510         [o_detached_time_sld setFloatValue: [o_time_sld floatValue]];
1511         [o_detached_time_sld setEnabled: [o_time_sld isEnabled]];
1512         [o_detached_time_fld setStringValue: [o_time_fld stringValue]];
1513         [o_detached_time_sld setHidden: [o_time_sld isHidden]];
1514     }
1515 }
1516
1517 - (void)updateVolumeSlider
1518 {
1519     playlist_t * p_playlist = pl_Get( VLCIntf );
1520     int i_volume = lroundf(aout_VolumeGet( p_playlist ) * AOUT_VOLUME_DEFAULT);
1521     BOOL b_muted = [[VLCCoreInteraction sharedInstance] isMuted];
1522
1523     if( !b_muted )
1524     {
1525         [o_volume_sld setIntValue: i_volume];
1526         [o_fspanel setVolumeLevel: i_volume];
1527     }
1528     else
1529         [o_volume_sld setIntValue: 0];
1530
1531     [o_volume_sld setEnabled: !b_muted];
1532     [o_volume_up_btn setEnabled: !b_muted];
1533 }
1534
1535 - (void)updateName
1536 {
1537     NSAutoreleasePool *o_pool = [[NSAutoreleasePool alloc] init];
1538     input_thread_t * p_input;
1539     p_input = pl_CurrentInput( VLCIntf );
1540     if( p_input )
1541     {
1542         NSString *aString;
1543         char *format = var_InheritString( VLCIntf, "input-title-format" );
1544         char *formated = str_format_meta( p_input, format );
1545         free( format );
1546         aString = [NSString stringWithUTF8String:formated];
1547         free( formated );
1548
1549         char *uri = input_item_GetURI( input_GetItem( p_input ) );
1550
1551         NSURL * o_url = [NSURL URLWithString: [NSString stringWithUTF8String: uri]];
1552         if ([o_url isFileURL])
1553         {
1554             [self setRepresentedURL: o_url];
1555             [o_detached_video_window setRepresentedURL: o_url];
1556         } else {
1557             [self setRepresentedURL: nil];
1558             [o_detached_video_window setRepresentedURL: nil];
1559         }
1560         free( uri );
1561
1562         if ([aString isEqualToString:@""])
1563         {
1564             if ([o_url isFileURL])
1565                 aString = [[NSFileManager defaultManager] displayNameAtPath: [o_url path]];
1566             else
1567                 aString = [o_url absoluteString];
1568         }
1569
1570         [self setTitle: aString];
1571         [o_fspanel setStreamTitle: aString];
1572         vlc_object_release( p_input );
1573     }
1574     else
1575     {
1576         [self setTitle: _NS("VLC media player")];
1577         [self setRepresentedURL: nil];
1578     }
1579
1580     [o_pool release];
1581 }
1582
1583 - (void)updateWindow
1584 {
1585     bool b_input = false;
1586     bool b_plmul = false;
1587     bool b_control = false;
1588     bool b_seekable = false;
1589     bool b_chapters = false;
1590
1591     playlist_t * p_playlist = pl_Get( VLCIntf );
1592
1593     PL_LOCK;
1594     b_plmul = playlist_CurrentSize( p_playlist ) > 1;
1595     PL_UNLOCK;
1596
1597     input_thread_t * p_input = playlist_CurrentInput( p_playlist );
1598
1599     bool b_buffering = NO;
1600
1601     if( ( b_input = ( p_input != NULL ) ) )
1602     {
1603         /* seekable streams */
1604         cachedInputState = input_GetState( p_input );
1605         if ( cachedInputState == INIT_S || cachedInputState == OPENING_S )
1606             b_buffering = YES;
1607
1608         /* seekable streams */
1609         b_seekable = var_GetBool( p_input, "can-seek" );
1610
1611         /* check whether slow/fast motion is possible */
1612         b_control = var_GetBool( p_input, "can-rate" );
1613
1614         /* chapters & titles */
1615         //FIXME! b_chapters = p_input->stream.i_area_nb > 1;
1616
1617         vlc_object_release( p_input );
1618     }
1619
1620     if( b_buffering )
1621     {
1622         [o_progress_bar startAnimation:self];
1623         [o_progress_bar setIndeterminate:YES];
1624         [o_progress_bar setHidden:NO];
1625     } else {
1626         [o_progress_bar stopAnimation:self];
1627         [o_progress_bar setHidden:YES];
1628     }
1629
1630     [o_stop_btn setEnabled: b_input];
1631     [o_fwd_btn setEnabled: (b_seekable || b_plmul || b_chapters)];
1632     [o_bwd_btn setEnabled: (b_seekable || b_plmul || b_chapters)];
1633     if (b_show_jump_buttons)
1634     {
1635         [o_prev_btn setEnabled: (b_seekable || b_plmul || b_chapters)];
1636         [o_next_btn setEnabled: (b_seekable || b_plmul || b_chapters)];
1637     }
1638     if (b_video_deco)
1639     {
1640         [o_detached_fwd_btn setEnabled: (b_seekable || b_plmul || b_chapters)];
1641         [o_detached_bwd_btn setEnabled: (b_seekable || b_plmul || b_chapters)];
1642     }
1643     [[VLCMainMenu sharedInstance] setRateControlsEnabled: b_control];
1644
1645     [o_time_sld setEnabled: b_seekable];
1646     [self updateTimeSlider];
1647     [o_fspanel setSeekable: b_seekable];
1648
1649     PL_LOCK;
1650     if ([[[VLCMain sharedInstance] playlist] currentPlaylistRoot] != p_playlist->p_local_category || p_playlist->p_local_category->i_children > 0)
1651         [self hideDropZone];
1652     else
1653         [self showDropZone];
1654     PL_UNLOCK;
1655     [o_sidebar_view setNeedsDisplay:YES];
1656 }
1657
1658 - (void)setPause
1659 {
1660     [o_play_btn setImage: o_pause_img];
1661     [o_play_btn setAlternateImage: o_pause_pressed_img];
1662     [o_play_btn setToolTip: _NS("Pause")];
1663     if (b_video_deco)
1664     {
1665         [o_detached_play_btn setImage: o_pause_img];
1666         [o_detached_play_btn setAlternateImage: o_pause_pressed_img];
1667         [o_detached_play_btn setToolTip: _NS("Pause")];
1668     }
1669     [o_fspanel setPause];
1670 }
1671
1672 - (void)setPlay
1673 {
1674     [o_play_btn setImage: o_play_img];
1675     [o_play_btn setAlternateImage: o_play_pressed_img];
1676     [o_play_btn setToolTip: _NS("Play")];
1677     if (b_video_deco)
1678     {
1679         [o_detached_play_btn setImage: o_play_img];
1680         [o_detached_play_btn setAlternateImage: o_play_pressed_img];
1681         [o_detached_play_btn setToolTip: _NS("Play")];
1682     }
1683     [o_fspanel setPlay];
1684 }
1685
1686 - (void)drawFancyGradientEffectForTimeSlider
1687 {
1688     if (OSX_LEOPARD)
1689         return;
1690
1691     NSAutoreleasePool * o_pool = [[NSAutoreleasePool alloc] init];
1692     CGFloat f_value = [o_time_sld knobPosition];
1693     if (f_value > 7.5)
1694     {
1695         NSRect oldFrame = [o_time_sld_fancygradient_view frame];
1696         if (f_value != oldFrame.size.width)
1697         {
1698             if ([o_time_sld_fancygradient_view isHidden])
1699                 [o_time_sld_fancygradient_view setHidden: NO];
1700             [o_time_sld_fancygradient_view setFrame: NSMakeRect( oldFrame.origin.x, oldFrame.origin.y, f_value, oldFrame.size.height )];
1701         }
1702
1703         if (b_nonembedded && b_video_deco)
1704         {
1705             f_value = [o_detached_time_sld knobPosition];
1706             oldFrame = [o_detached_time_sld_fancygradient_view frame];
1707             if (f_value != oldFrame.size.width)
1708             {
1709                 if ([o_detached_time_sld_fancygradient_view isHidden])
1710                     [o_detached_time_sld_fancygradient_view setHidden: NO];
1711                 [o_detached_time_sld_fancygradient_view setFrame: NSMakeRect( oldFrame.origin.x, oldFrame.origin.y, f_value, oldFrame.size.height )];
1712             }
1713         }
1714     }
1715     else
1716     {
1717         NSRect frame;
1718         frame = [o_time_sld_fancygradient_view frame];
1719         if (frame.size.width > 0)
1720         {
1721             frame.size.width = 0;
1722             [o_time_sld_fancygradient_view setFrame: frame];
1723
1724             if (b_video_deco)
1725             {
1726                 frame = [o_detached_time_sld_fancygradient_view frame];
1727                 frame.size.width = 0;
1728                 [o_detached_time_sld_fancygradient_view setFrame: frame];
1729             }
1730         }
1731         [o_time_sld_fancygradient_view setHidden: YES];
1732         if (b_video_deco)
1733             [o_detached_time_sld_fancygradient_view setHidden: YES];
1734     }
1735     [o_pool release];
1736 }
1737
1738 #pragma mark -
1739 #pragma mark Video Output handling
1740 - (id)videoView
1741 {
1742     return o_video_view;
1743 }
1744
1745 - (id)setupVideoView
1746 {
1747     vout_thread_t *p_vout = getVout();
1748     if ((config_GetInt( VLCIntf, "embedded-video" ) || b_nativeFullscreenMode) && b_video_deco)
1749     {
1750         if ([o_video_view window] != self)
1751         {
1752             [o_video_view removeFromSuperviewWithoutNeedingDisplay];
1753             [o_video_view setFrame: [o_split_view frame]];
1754             [[self contentView] addSubview:o_video_view positioned:NSWindowAbove relativeTo:nil];
1755         }
1756         b_nonembedded = NO;
1757     }
1758     else
1759     {
1760         if ([o_video_view superview] != NULL)
1761             [o_video_view removeFromSuperviewWithoutNeedingDisplay];
1762
1763         NSRect frame = [o_detached_video_window frame];
1764         NSRect videoFrame = [o_video_view frame];
1765         frame.size.width = videoFrame.size.width;
1766         if (b_video_deco)
1767             frame.size.height = videoFrame.size.height + [o_detached_bottombar_view frame].size.height + [o_titlebar_view frame].size.height;
1768         else
1769         {
1770             frame.size.height = videoFrame.size.height;
1771             videoFrame.origin.y = .0;
1772             videoFrame.origin.x = .0;
1773             [o_video_view setFrame: videoFrame];
1774         }
1775         [o_detached_video_window setFrame: frame display: NO];
1776         [[o_detached_video_window contentView] addSubview: o_video_view positioned:NSWindowAbove relativeTo:nil];
1777         [o_detached_video_window setLevel:NSNormalWindowLevel];
1778         [o_detached_video_window useOptimizedDrawing: YES];
1779         [o_detached_video_window center];
1780         b_nonembedded = YES;
1781     }
1782     [[o_video_view window] makeKeyAndOrderFront: self];
1783     [[o_video_view window] setAlphaValue: config_GetFloat( VLCIntf, "macosx-opaqueness" )];
1784
1785     if (p_vout)
1786     {
1787         if( var_GetBool( p_vout, "video-on-top" ) )
1788             [[o_video_view window] setLevel: NSStatusWindowLevel];
1789         else
1790             [[o_video_view window] setLevel: NSNormalWindowLevel];
1791         vlc_object_release( p_vout );
1792     }
1793     return o_video_view;
1794 }
1795
1796 - (void)setVideoplayEnabled
1797 {
1798     BOOL b_videoPlayback = [[VLCMain sharedInstance] activeVideoPlayback];
1799
1800     if( b_videoPlayback )
1801     {
1802         // look for 'start at fullscreen'
1803         [[VLCMain sharedInstance] fullscreenChanged];
1804     }
1805     else
1806     {
1807         [self makeFirstResponder: nil];
1808         [o_detached_video_window orderOut: nil];
1809
1810         // restore alpha value to 1 for the case that macosx-opaqueness is set to < 1
1811         [self setAlphaValue:1.0];
1812     }
1813
1814     if( b_nativeFullscreenMode )
1815     {
1816         if( [NSApp presentationOptions] & NSApplicationPresentationFullScreen )
1817             [o_bottombar_view setHidden: b_videoPlayback];
1818         else
1819             [o_bottombar_view setHidden: NO];
1820         if( b_videoPlayback && b_fullscreen )
1821             [o_fspanel setActive: nil];
1822         if( !b_videoPlayback )
1823             [o_fspanel setNonActive: nil];
1824     }
1825
1826     if (!b_videoPlayback && b_fullscreen)
1827     {
1828         if (!b_nativeFullscreenMode)
1829             [[VLCCoreInteraction sharedInstance] toggleFullscreen];
1830     }
1831 }
1832
1833 - (void)resizeWindow
1834 {
1835     if( b_fullscreen || ( b_nativeFullscreenMode && [NSApp presentationOptions] & NSApplicationPresentationFullScreen ) )
1836         return;
1837
1838     id o_videoWindow = b_nonembedded ? o_detached_video_window : self;
1839     NSSize windowMinSize = [o_videoWindow minSize];
1840     NSRect screenFrame = [[o_videoWindow screen] visibleFrame];
1841
1842     NSPoint topleftbase = NSMakePoint( 0, [o_videoWindow frame].size.height );
1843     NSPoint topleftscreen = [o_videoWindow convertBaseToScreen: topleftbase];
1844
1845     unsigned int i_width = nativeVideoSize.width;
1846     unsigned int i_height = nativeVideoSize.height;
1847     if (i_width < windowMinSize.width)
1848         i_width = windowMinSize.width;
1849     if (i_height < f_min_video_height)
1850         i_height = f_min_video_height;
1851
1852     /* Calculate the window's new size */
1853     NSRect new_frame;
1854     new_frame.size.width = [o_videoWindow frame].size.width - [o_video_view frame].size.width + i_width;
1855     new_frame.size.height = [o_videoWindow frame].size.height - [o_video_view frame].size.height + i_height;
1856     new_frame.origin.x = topleftscreen.x;
1857     new_frame.origin.y = topleftscreen.y - new_frame.size.height;
1858
1859     /* make sure the window doesn't exceed the screen size the window is on */
1860     if( new_frame.size.width > screenFrame.size.width )
1861     {
1862         new_frame.size.width = screenFrame.size.width;
1863         new_frame.origin.x = screenFrame.origin.x;
1864     }
1865     if( new_frame.size.height > screenFrame.size.height )
1866     {
1867         new_frame.size.height = screenFrame.size.height;
1868         new_frame.origin.y = screenFrame.origin.y;
1869     }
1870     if( new_frame.origin.y < screenFrame.origin.y )
1871         new_frame.origin.y = screenFrame.origin.y;
1872
1873     CGFloat right_screen_point = screenFrame.origin.x + screenFrame.size.width;
1874     CGFloat right_window_point = new_frame.origin.x + new_frame.size.width;
1875     if( right_window_point > right_screen_point )
1876         new_frame.origin.x -= ( right_window_point - right_screen_point );
1877
1878     [[o_videoWindow animator] setFrame:new_frame display:YES];
1879 }
1880
1881 - (void)setNativeVideoSize:(NSSize)size
1882 {
1883     nativeVideoSize = size;
1884
1885     if( config_GetInt( VLCIntf, "macosx-video-autoresize" ) && !b_fullscreen )
1886         [self performSelectorOnMainThread:@selector(resizeWindow) withObject:nil waitUntilDone:NO];
1887 }
1888
1889 //  Called automatically if window's acceptsMouseMovedEvents property is true
1890 - (void)mouseMoved:(NSEvent *)theEvent
1891 {
1892     if (b_fullscreen)
1893         [self recreateHideMouseTimer];
1894
1895     [super mouseMoved: theEvent];
1896 }
1897
1898 - (void)recreateHideMouseTimer
1899 {
1900     if (t_hide_mouse_timer != nil) {
1901         [t_hide_mouse_timer invalidate];
1902         [t_hide_mouse_timer release];
1903     }
1904
1905     t_hide_mouse_timer = [NSTimer scheduledTimerWithTimeInterval:2
1906                                                           target:self
1907                                                         selector:@selector(hideMouseCursor:)
1908                                                         userInfo:nil
1909                                                          repeats:NO];
1910     [t_hide_mouse_timer retain];
1911 }
1912
1913 //  NSTimer selectors require this function signature as per Apple's docs
1914 - (void)hideMouseCursor:(NSTimer *)timer
1915 {
1916     [NSCursor setHiddenUntilMouseMoves: YES];
1917 }
1918
1919 #pragma mark -
1920 #pragma mark Fullscreen support
1921 - (void)showFullscreenController
1922 {
1923      if (b_fullscreen && [[VLCMain sharedInstance] activeVideoPlayback] )
1924         [o_fspanel fadeIn];
1925 }
1926
1927 - (BOOL)isFullscreen
1928 {
1929     return b_fullscreen;
1930 }
1931
1932 - (void)lockFullscreenAnimation
1933 {
1934     [o_animation_lock lock];
1935 }
1936
1937 - (void)unlockFullscreenAnimation
1938 {
1939     [o_animation_lock unlock];
1940 }
1941
1942 - (void)enterFullscreen
1943 {
1944     NSMutableDictionary *dict1, *dict2;
1945     NSScreen *screen;
1946     NSRect screen_rect;
1947     NSRect rect;
1948     BOOL blackout_other_displays = config_GetInt( VLCIntf, "macosx-black" );
1949     id o_videoWindow = b_nonembedded ? o_detached_video_window : self;
1950
1951     screen = [NSScreen screenWithDisplayID:(CGDirectDisplayID)config_GetInt( VLCIntf, "macosx-vdev" )];
1952     [self lockFullscreenAnimation];
1953
1954     if (!screen)
1955     {
1956         msg_Dbg( VLCIntf, "chosen screen isn't present, using current screen for fullscreen mode" );
1957         screen = [o_videoWindow screen];
1958     }
1959     if (!screen)
1960     {
1961         msg_Dbg( VLCIntf, "Using deepest screen" );
1962         screen = [NSScreen deepestScreen];
1963     }
1964
1965     screen_rect = [screen frame];
1966
1967     [o_fullscreen_btn setState: YES];
1968     if (b_video_deco)
1969         [o_detached_fullscreen_btn setState: YES];
1970
1971     [self recreateHideMouseTimer];
1972
1973     if( blackout_other_displays )
1974         [screen blackoutOtherScreens];
1975
1976     /* Make sure we don't see the window flashes in float-on-top mode */
1977     i_originalLevel = [o_videoWindow level];
1978     [o_videoWindow setLevel:NSNormalWindowLevel];
1979
1980     /* Only create the o_fullscreen_window if we are not in the middle of the zooming animation */
1981     if (!o_fullscreen_window)
1982     {
1983         /* We can't change the styleMask of an already created NSWindow, so we create another window, and do eye catching stuff */
1984
1985         rect = [[o_video_view superview] convertRect: [o_video_view frame] toView: nil]; /* Convert to Window base coord */
1986         rect.origin.x += [o_videoWindow frame].origin.x;
1987         rect.origin.y += [o_videoWindow frame].origin.y;
1988         o_fullscreen_window = [[VLCWindow alloc] initWithContentRect:rect styleMask: NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:YES];
1989         [o_fullscreen_window setFullscreen: YES];
1990         [o_fullscreen_window setBackgroundColor: [NSColor blackColor]];
1991         [o_fullscreen_window setCanBecomeKeyWindow: YES];
1992         [o_fullscreen_window setCanBecomeMainWindow: YES];
1993
1994         if (![o_videoWindow isVisible] || [o_videoWindow alphaValue] == 0.0)
1995         {
1996             /* We don't animate if we are not visible, instead we
1997              * simply fade the display */
1998             CGDisplayFadeReservationToken token;
1999
2000             if( blackout_other_displays )
2001             {
2002                 CGAcquireDisplayFadeReservation( kCGMaxDisplayReservationInterval, &token );
2003                 CGDisplayFade( token, 0.5, kCGDisplayBlendNormal, kCGDisplayBlendSolidColor, 0, 0, 0, YES );
2004             }
2005
2006             if ([screen isMainScreen])
2007             {
2008                 if (OSX_LEOPARD)
2009                     SetSystemUIMode( kUIModeAllHidden, kUIOptionAutoShowMenuBar);
2010                 else
2011                     [NSApp setPresentationOptions:(NSApplicationPresentationAutoHideDock | NSApplicationPresentationAutoHideMenuBar)];
2012             }
2013
2014             [[o_video_view superview] replaceSubview:o_video_view with:o_temp_view];
2015             [o_temp_view setFrame:[o_video_view frame]];
2016             [o_fullscreen_window setContentView:o_video_view];
2017
2018             [o_fullscreen_window makeKeyAndOrderFront:self];
2019             [o_fullscreen_window orderFront:self animate:YES];
2020
2021             [o_fullscreen_window setFrame:screen_rect display:YES animate:YES];
2022             [o_fullscreen_window setLevel:NSNormalWindowLevel];
2023
2024             if( blackout_other_displays )
2025             {
2026                 CGDisplayFade( token, 0.3, kCGDisplayBlendSolidColor, kCGDisplayBlendNormal, 0, 0, 0, NO );
2027                 CGReleaseDisplayFadeReservation( token );
2028             }
2029
2030             /* Will release the lock */
2031             [self hasBecomeFullscreen];
2032
2033             return;
2034         }
2035
2036         /* Make sure we don't see the o_video_view disappearing of the screen during this operation */
2037         NSDisableScreenUpdates();
2038         [[o_video_view superview] replaceSubview:o_video_view with:o_temp_view];
2039         [o_temp_view setFrame:[o_video_view frame]];
2040         [o_fullscreen_window setContentView:o_video_view];
2041         [o_fullscreen_window makeKeyAndOrderFront:self];
2042         NSEnableScreenUpdates();
2043     }
2044
2045     /* We are in fullscreen (and no animation is running) */
2046     if (b_fullscreen)
2047     {
2048         /* Make sure we are hidden */
2049         [o_videoWindow orderOut: self];
2050
2051         [self unlockFullscreenAnimation];
2052         return;
2053     }
2054
2055     if (o_fullscreen_anim1)
2056     {
2057         [o_fullscreen_anim1 stopAnimation];
2058         [o_fullscreen_anim1 release];
2059     }
2060     if (o_fullscreen_anim2)
2061     {
2062         [o_fullscreen_anim2 stopAnimation];
2063         [o_fullscreen_anim2 release];
2064     }
2065
2066     if ([screen isMainScreen])
2067     {
2068         if (OSX_LEOPARD)
2069             SetSystemUIMode( kUIModeAllHidden, kUIOptionAutoShowMenuBar);
2070         else
2071             [NSApp setPresentationOptions:(NSApplicationPresentationAutoHideDock | NSApplicationPresentationAutoHideMenuBar)];
2072     }
2073
2074     dict1 = [[NSMutableDictionary alloc] initWithCapacity:2];
2075     dict2 = [[NSMutableDictionary alloc] initWithCapacity:3];
2076
2077     [dict1 setObject:o_videoWindow forKey:NSViewAnimationTargetKey];
2078     [dict1 setObject:NSViewAnimationFadeOutEffect forKey:NSViewAnimationEffectKey];
2079
2080     [dict2 setObject:o_fullscreen_window forKey:NSViewAnimationTargetKey];
2081     [dict2 setObject:[NSValue valueWithRect:[o_fullscreen_window frame]] forKey:NSViewAnimationStartFrameKey];
2082     [dict2 setObject:[NSValue valueWithRect:screen_rect] forKey:NSViewAnimationEndFrameKey];
2083
2084     /* Strategy with NSAnimation allocation:
2085      - Keep at most 2 animation at a time
2086      - leaveFullscreen/enterFullscreen are the only responsible for releasing and alloc-ing
2087      */
2088     o_fullscreen_anim1 = [[NSViewAnimation alloc] initWithViewAnimations:[NSArray arrayWithObject:dict1]];
2089     o_fullscreen_anim2 = [[NSViewAnimation alloc] initWithViewAnimations:[NSArray arrayWithObject:dict2]];
2090
2091     [dict1 release];
2092     [dict2 release];
2093
2094     [o_fullscreen_anim1 setAnimationBlockingMode: NSAnimationNonblocking];
2095     [o_fullscreen_anim1 setDuration: 0.3];
2096     [o_fullscreen_anim1 setFrameRate: 30];
2097     [o_fullscreen_anim2 setAnimationBlockingMode: NSAnimationNonblocking];
2098     [o_fullscreen_anim2 setDuration: 0.2];
2099     [o_fullscreen_anim2 setFrameRate: 30];
2100
2101     [o_fullscreen_anim2 setDelegate: self];
2102     [o_fullscreen_anim2 startWhenAnimation: o_fullscreen_anim1 reachesProgress: 1.0];
2103
2104     [o_fullscreen_anim1 startAnimation];
2105     /* fullscreenAnimation will be unlocked when animation ends */
2106 }
2107
2108 - (void)hasBecomeFullscreen
2109 {
2110     if( [[o_video_view subviews] count] > 0 )
2111         [o_fullscreen_window makeFirstResponder: [[o_video_view subviews] objectAtIndex:0]];
2112
2113     [o_fullscreen_window makeKeyWindow];
2114     [o_fullscreen_window setAcceptsMouseMovedEvents: YES];
2115
2116     /* tell the fspanel to move itself to front next time it's triggered */
2117     [o_fspanel setVoutWasUpdated: (int)[[o_fullscreen_window screen] displayID]];
2118     [o_fspanel setActive: nil];
2119
2120     id o_videoWindow = b_nonembedded ? o_detached_video_window : self;
2121     if( [o_videoWindow isVisible] )
2122         [o_videoWindow orderOut: self];
2123
2124     b_fullscreen = YES;
2125     [self unlockFullscreenAnimation];
2126 }
2127
2128 - (void)leaveFullscreen
2129 {
2130     [self leaveFullscreenAndFadeOut: NO];
2131 }
2132
2133 - (void)leaveFullscreenAndFadeOut: (BOOL)fadeout
2134 {
2135     NSMutableDictionary *dict1, *dict2;
2136     NSRect frame;
2137     BOOL blackout_other_displays = config_GetInt( VLCIntf, "macosx-black" );
2138
2139     [self lockFullscreenAnimation];
2140
2141     [o_fullscreen_btn setState: NO];
2142     if (b_video_deco)
2143         [o_detached_fullscreen_btn setState: NO];
2144
2145     /* We always try to do so */
2146     [NSScreen unblackoutScreens];
2147
2148     vout_thread_t *p_vout = getVout();
2149     if (p_vout)
2150     {
2151         if( var_GetBool( p_vout, "video-on-top" ) )
2152             [[o_video_view window] setLevel: NSStatusWindowLevel];
2153         else
2154             [[o_video_view window] setLevel: NSNormalWindowLevel];
2155         vlc_object_release( p_vout );
2156     }
2157     [[o_video_view window] makeKeyAndOrderFront: nil];
2158
2159     /* Don't do anything if o_fullscreen_window is already closed */
2160     if (!o_fullscreen_window)
2161     {
2162         [self unlockFullscreenAnimation];
2163         return;
2164     }
2165
2166     if (fadeout)
2167     {
2168         /* We don't animate if we are not visible, instead we
2169          * simply fade the display */
2170         CGDisplayFadeReservationToken token;
2171
2172         if( blackout_other_displays )
2173         {
2174             CGAcquireDisplayFadeReservation( kCGMaxDisplayReservationInterval, &token );
2175             CGDisplayFade( token, 0.3, kCGDisplayBlendNormal, kCGDisplayBlendSolidColor, 0, 0, 0, YES );
2176         }
2177
2178         [o_fspanel setNonActive: nil];
2179         if (OSX_LEOPARD)
2180             SetSystemUIMode( kUIModeNormal, kUIOptionAutoShowMenuBar);
2181         else
2182             [NSApp setPresentationOptions: NSApplicationPresentationDefault];
2183
2184         /* Will release the lock */
2185         [self hasEndedFullscreen];
2186
2187         /* Our window is hidden, and might be faded. We need to workaround that, so note it
2188          * here */
2189         b_window_is_invisible = YES;
2190
2191         if( blackout_other_displays )
2192         {
2193             CGDisplayFade( token, 0.5, kCGDisplayBlendSolidColor, kCGDisplayBlendNormal, 0, 0, 0, NO );
2194             CGReleaseDisplayFadeReservation( token );
2195         }
2196
2197         return;
2198     }
2199
2200     id o_videoWindow = b_nonembedded ? o_detached_video_window : self;
2201
2202     [o_videoWindow setAlphaValue: 0.0];
2203     [o_videoWindow orderFront: self];
2204     [[o_video_view window] orderFront: self];
2205
2206     [o_fspanel setNonActive: nil];
2207     if (OSX_LEOPARD)
2208         SetSystemUIMode( kUIModeNormal, kUIOptionAutoShowMenuBar);
2209     else
2210         [NSApp setPresentationOptions:(NSApplicationPresentationDefault)];
2211
2212     if (o_fullscreen_anim1)
2213     {
2214         [o_fullscreen_anim1 stopAnimation];
2215         [o_fullscreen_anim1 release];
2216     }
2217     if (o_fullscreen_anim2)
2218     {
2219         [o_fullscreen_anim2 stopAnimation];
2220         [o_fullscreen_anim2 release];
2221     }
2222
2223     frame = [[o_temp_view superview] convertRect: [o_temp_view frame] toView: nil]; /* Convert to Window base coord */
2224     frame.origin.x += [o_videoWindow frame].origin.x;
2225     frame.origin.y += [o_videoWindow frame].origin.y;
2226
2227     dict2 = [[NSMutableDictionary alloc] initWithCapacity:2];
2228     [dict2 setObject:o_videoWindow forKey:NSViewAnimationTargetKey];
2229     [dict2 setObject:NSViewAnimationFadeInEffect forKey:NSViewAnimationEffectKey];
2230
2231     o_fullscreen_anim2 = [[NSViewAnimation alloc] initWithViewAnimations:[NSArray arrayWithObjects:dict2, nil]];
2232     [dict2 release];
2233
2234     [o_fullscreen_anim2 setAnimationBlockingMode: NSAnimationNonblocking];
2235     [o_fullscreen_anim2 setDuration: 0.3];
2236     [o_fullscreen_anim2 setFrameRate: 30];
2237
2238     [o_fullscreen_anim2 setDelegate: self];
2239
2240     dict1 = [[NSMutableDictionary alloc] initWithCapacity:3];
2241
2242     [dict1 setObject:o_fullscreen_window forKey:NSViewAnimationTargetKey];
2243     [dict1 setObject:[NSValue valueWithRect:[o_fullscreen_window frame]] forKey:NSViewAnimationStartFrameKey];
2244     [dict1 setObject:[NSValue valueWithRect:frame] forKey:NSViewAnimationEndFrameKey];
2245
2246     o_fullscreen_anim1 = [[NSViewAnimation alloc] initWithViewAnimations:[NSArray arrayWithObjects:dict1, nil]];
2247     [dict1 release];
2248
2249     [o_fullscreen_anim1 setAnimationBlockingMode: NSAnimationNonblocking];
2250     [o_fullscreen_anim1 setDuration: 0.2];
2251     [o_fullscreen_anim1 setFrameRate: 30];
2252     [o_fullscreen_anim2 startWhenAnimation: o_fullscreen_anim1 reachesProgress: 1.0];
2253
2254     /* Make sure o_fullscreen_window is the frontmost window */
2255     [o_fullscreen_window orderFront: self];
2256
2257     [o_fullscreen_anim1 startAnimation];
2258     /* fullscreenAnimation will be unlocked when animation ends */
2259 }
2260
2261 - (void)hasEndedFullscreen
2262 {
2263     b_fullscreen = NO;
2264
2265     /* This function is private and should be only triggered at the end of the fullscreen change animation */
2266     /* Make sure we don't see the o_video_view disappearing of the screen during this operation */
2267     NSDisableScreenUpdates();
2268     [o_video_view retain];
2269     [o_video_view removeFromSuperviewWithoutNeedingDisplay];
2270     [[o_temp_view superview] replaceSubview:o_temp_view with:o_video_view];
2271     [o_video_view release];
2272     [o_video_view setFrame:[o_temp_view frame]];
2273     if( [[o_video_view subviews] count] > 0 )
2274         [[o_video_view window] makeFirstResponder: [[o_video_view subviews] objectAtIndex:0]];
2275     if( !b_nonembedded )
2276             [super makeKeyAndOrderFront:self]; /* our version contains a workaround */
2277     else
2278         [[o_video_view window] makeKeyAndOrderFront: self];
2279     [o_fullscreen_window orderOut: self];
2280     NSEnableScreenUpdates();
2281
2282     [o_fullscreen_window release];
2283     o_fullscreen_window = nil;
2284     [[o_video_view window] setLevel:i_originalLevel];
2285     [[o_video_view window] setAlphaValue: config_GetFloat( VLCIntf, "macosx-opaqueness" )];
2286
2287     // if we quit fullscreen because there is no video anymore, make sure non-embedded window is not visible
2288     if( ![[VLCMain sharedInstance] activeVideoPlayback] && b_nonembedded )
2289         [o_detached_video_window orderOut: self];
2290
2291     [self unlockFullscreenAnimation];
2292 }
2293
2294 - (void)animationDidEnd:(NSAnimation*)animation
2295 {
2296     NSArray *viewAnimations;
2297     if( o_makekey_anim == animation )
2298     {
2299         [o_makekey_anim release];
2300         return;
2301     }
2302     if ([animation currentValue] < 1.0)
2303         return;
2304
2305     /* Fullscreen ended or started (we are a delegate only for leaveFullscreen's/enterFullscren's anim2) */
2306     viewAnimations = [o_fullscreen_anim2 viewAnimations];
2307     if ([viewAnimations count] >=1 &&
2308         [[[viewAnimations objectAtIndex: 0] objectForKey: NSViewAnimationEffectKey] isEqualToString:NSViewAnimationFadeInEffect])
2309     {
2310         /* Fullscreen ended */
2311         [self hasEndedFullscreen];
2312     }
2313     else
2314     {
2315         /* Fullscreen started */
2316         [self hasBecomeFullscreen];
2317     }
2318 }
2319
2320 - (void)makeKeyAndOrderFront: (id)sender
2321 {
2322     /* Hack
2323      * when we exit fullscreen and fade out, we may endup in
2324      * having a window that is faded. We can't have it fade in unless we
2325      * animate again. */
2326
2327     if(!b_window_is_invisible)
2328     {
2329         /* Make sure we don't do it too much */
2330         [super makeKeyAndOrderFront: sender];
2331         return;
2332     }
2333
2334     [super setAlphaValue:0.0f];
2335     [super makeKeyAndOrderFront: sender];
2336
2337     NSMutableDictionary * dict = [[NSMutableDictionary alloc] initWithCapacity:2];
2338     [dict setObject:self forKey:NSViewAnimationTargetKey];
2339     [dict setObject:NSViewAnimationFadeInEffect forKey:NSViewAnimationEffectKey];
2340
2341     o_makekey_anim = [[NSViewAnimation alloc] initWithViewAnimations:[NSArray arrayWithObject:dict]];
2342     [dict release];
2343
2344     [o_makekey_anim setAnimationBlockingMode: NSAnimationNonblocking];
2345     [o_makekey_anim setDuration: 0.1];
2346     [o_makekey_anim setFrameRate: 30];
2347     [o_makekey_anim setDelegate: self];
2348
2349     [o_makekey_anim startAnimation];
2350     b_window_is_invisible = NO;
2351
2352     /* fullscreenAnimation will be unlocked when animation ends */
2353 }
2354
2355 #pragma mark -
2356 #pragma mark Lion native fullscreen handling
2357 - (void)windowWillEnterFullScreen:(NSNotification *)notification
2358 {
2359     // workaround, see #6668
2360     [NSApp setPresentationOptions:(NSApplicationPresentationFullScreen | NSApplicationPresentationAutoHideDock | NSApplicationPresentationAutoHideMenuBar)];
2361
2362     var_SetBool( pl_Get( VLCIntf ), "fullscreen", true );
2363
2364     vout_thread_t *p_vout = getVout();
2365     if( p_vout )
2366     {
2367         var_SetBool( p_vout, "fullscreen", true );
2368         vlc_object_release( p_vout );
2369     }
2370
2371     [o_video_view setFrame: [[self contentView] frame]];
2372     b_fullscreen = YES;
2373
2374     [self recreateHideMouseTimer];
2375     i_originalLevel = [self level];
2376     [self setLevel:NSNormalWindowLevel];
2377
2378     if (b_dark_interface)
2379     {
2380         [o_titlebar_view removeFromSuperviewWithoutNeedingDisplay];
2381
2382         NSRect winrect;
2383         CGFloat f_titleBarHeight = [o_titlebar_view frame].size.height;
2384         winrect = [self frame];
2385
2386         winrect.size.height = winrect.size.height - f_titleBarHeight;
2387         [self setFrame: winrect display:NO animate:NO];
2388         winrect = [o_split_view frame];
2389         winrect.size.height = winrect.size.height + f_titleBarHeight;
2390         [o_split_view setFrame: winrect];
2391     }
2392
2393     if ([[VLCMain sharedInstance] activeVideoPlayback])
2394         [o_bottombar_view setHidden: YES];
2395
2396     [self setMovableByWindowBackground: NO];
2397 }
2398
2399 - (void)windowDidEnterFullScreen:(NSNotification *)notification
2400 {
2401     // Indeed, we somehow can have an "inactive" fullscreen (but a visible window!).
2402     // But this creates some problems when leaving fs over remote intfs, so activate app here.
2403     [NSApp activateIgnoringOtherApps:YES];
2404
2405     [o_fspanel setVoutWasUpdated: (int)[[self screen] displayID]];
2406     [o_fspanel setActive: nil];
2407 }
2408
2409 - (void)windowWillExitFullScreen:(NSNotification *)notification
2410 {
2411
2412     var_SetBool( pl_Get( VLCIntf ), "fullscreen", false );
2413
2414     vout_thread_t *p_vout = getVout();
2415     if( p_vout )
2416     {
2417         var_SetBool( p_vout, "fullscreen", false );
2418         vlc_object_release( p_vout );
2419     }
2420
2421     [o_video_view setFrame: [o_split_view frame]];
2422     [NSCursor setHiddenUntilMouseMoves: NO];
2423     [o_fspanel setNonActive: nil];
2424     [self setLevel:i_originalLevel];
2425     b_fullscreen = NO;
2426
2427     if (b_dark_interface)
2428     {
2429         NSRect winrect;
2430         CGFloat f_titleBarHeight = [o_titlebar_view frame].size.height;
2431         winrect = [self frame];
2432
2433         [o_titlebar_view setFrame: NSMakeRect( 0, winrect.size.height - f_titleBarHeight,
2434                                               winrect.size.width, f_titleBarHeight )];
2435         [[self contentView] addSubview: o_titlebar_view];
2436
2437         winrect.size.height = winrect.size.height + f_titleBarHeight;
2438         [self setFrame: winrect display:NO animate:NO];
2439         winrect = [o_split_view frame];
2440         winrect.size.height = winrect.size.height - f_titleBarHeight;
2441         [o_split_view setFrame: winrect];
2442         [o_video_view setFrame: winrect];
2443     }
2444
2445     if ([[VLCMain sharedInstance] activeVideoPlayback])
2446         [o_bottombar_view setHidden: NO];
2447
2448     [self setMovableByWindowBackground: YES];
2449 }
2450
2451 #pragma mark -
2452 #pragma mark split view delegate
2453 - (CGFloat)splitView:(NSSplitView *)splitView constrainMaxCoordinate:(CGFloat)proposedMax ofSubviewAt:(NSInteger)dividerIndex
2454 {
2455     if (dividerIndex == 0)
2456         return 300.;
2457     else
2458         return proposedMax;
2459 }
2460
2461 - (CGFloat)splitView:(NSSplitView *)splitView constrainMinCoordinate:(CGFloat)proposedMin ofSubviewAt:(NSInteger)dividerIndex
2462 {
2463     if (dividerIndex == 0)
2464         return 100.;
2465     else
2466         return proposedMin;
2467 }
2468
2469 - (BOOL)splitView:(NSSplitView *)splitView canCollapseSubview:(NSView *)subview
2470 {
2471     return ([subview isEqual:o_left_split_view]);
2472 }
2473
2474 - (BOOL)splitView:(NSSplitView *)splitView shouldAdjustSizeOfSubview:(NSView *)subview
2475 {
2476     if ([subview isEqual:o_left_split_view])
2477         return NO;
2478     return YES;
2479 }
2480
2481 #pragma mark -
2482 #pragma mark Side Bar Data handling
2483 /* taken under BSD-new from the PXSourceList sample project, adapted for VLC */
2484 - (NSUInteger)sourceList:(PXSourceList*)sourceList numberOfChildrenOfItem:(id)item
2485 {
2486     //Works the same way as the NSOutlineView data source: `nil` means a parent item
2487     if(item==nil)
2488         return [o_sidebaritems count];
2489     else
2490         return [[item children] count];
2491 }
2492
2493
2494 - (id)sourceList:(PXSourceList*)aSourceList child:(NSUInteger)index ofItem:(id)item
2495 {
2496     //Works the same way as the NSOutlineView data source: `nil` means a parent item
2497     if(item==nil)
2498         return [o_sidebaritems objectAtIndex:index];
2499     else
2500         return [[item children] objectAtIndex:index];
2501 }
2502
2503
2504 - (id)sourceList:(PXSourceList*)aSourceList objectValueForItem:(id)item
2505 {
2506     return [item title];
2507 }
2508
2509 - (void)sourceList:(PXSourceList*)aSourceList setObjectValue:(id)object forItem:(id)item
2510 {
2511     [item setTitle:object];
2512 }
2513
2514 - (BOOL)sourceList:(PXSourceList*)aSourceList isItemExpandable:(id)item
2515 {
2516     return [item hasChildren];
2517 }
2518
2519
2520 - (BOOL)sourceList:(PXSourceList*)aSourceList itemHasBadge:(id)item
2521 {
2522     if ([[item identifier] isEqualToString: @"playlist"] || [[item identifier] isEqualToString: @"medialibrary"])
2523         return YES;
2524
2525     return [item hasBadge];
2526 }
2527
2528
2529 - (NSInteger)sourceList:(PXSourceList*)aSourceList badgeValueForItem:(id)item
2530 {
2531     playlist_t * p_playlist = pl_Get( VLCIntf );
2532     NSInteger i_playlist_size;
2533
2534     if ([[item identifier] isEqualToString: @"playlist"])
2535     {
2536         PL_LOCK;
2537         i_playlist_size = p_playlist->p_local_category->i_children;
2538         PL_UNLOCK;
2539
2540         return i_playlist_size;
2541     }
2542     if ([[item identifier] isEqualToString: @"medialibrary"])
2543     {
2544         PL_LOCK;
2545         i_playlist_size = p_playlist->p_ml_category->i_children;
2546         PL_UNLOCK;
2547
2548         return i_playlist_size;
2549     }
2550
2551     return [item badgeValue];
2552 }
2553
2554
2555 - (BOOL)sourceList:(PXSourceList*)aSourceList itemHasIcon:(id)item
2556 {
2557     return [item hasIcon];
2558 }
2559
2560
2561 - (NSImage*)sourceList:(PXSourceList*)aSourceList iconForItem:(id)item
2562 {
2563     return [item icon];
2564 }
2565
2566 - (NSMenu*)sourceList:(PXSourceList*)aSourceList menuForEvent:(NSEvent*)theEvent item:(id)item
2567 {
2568     if ([theEvent type] == NSRightMouseDown || ([theEvent type] == NSLeftMouseDown && ([theEvent modifierFlags] & NSControlKeyMask) == NSControlKeyMask))
2569     {
2570         if (item != nil)
2571         {
2572             NSMenu * m;
2573             if ([item sdtype] > 0)
2574             {
2575                 m = [[NSMenu alloc] init];
2576                 playlist_t * p_playlist = pl_Get( VLCIntf );
2577                 BOOL sd_loaded = playlist_IsServicesDiscoveryLoaded( p_playlist, [[item identifier] UTF8String] );
2578                 if (!sd_loaded)
2579                     [m addItemWithTitle:_NS("Enable") action:@selector(sdmenuhandler:) keyEquivalent:@""];
2580                 else
2581                     [m addItemWithTitle:_NS("Disable") action:@selector(sdmenuhandler:) keyEquivalent:@""];
2582                 [[m itemAtIndex:0] setRepresentedObject: [item identifier]];
2583             }
2584             return [m autorelease];
2585         }
2586     }
2587
2588     return nil;
2589 }
2590
2591 - (IBAction)sdmenuhandler:(id)sender
2592 {
2593     NSString * identifier = [sender representedObject];
2594     if ([identifier length] > 0 && ![identifier isEqualToString:@"lua{sd='freebox',longname='Freebox TV'}"])
2595     {
2596         playlist_t * p_playlist = pl_Get( VLCIntf );
2597         BOOL sd_loaded = playlist_IsServicesDiscoveryLoaded( p_playlist, [identifier UTF8String] );
2598
2599         if (!sd_loaded)
2600             playlist_ServicesDiscoveryAdd( p_playlist, [identifier UTF8String] );
2601         else
2602             playlist_ServicesDiscoveryRemove( p_playlist, [identifier UTF8String] );
2603     }
2604 }
2605
2606 #pragma mark -
2607 #pragma mark Side Bar Delegate Methods
2608 /* taken under BSD-new from the PXSourceList sample project, adapted for VLC */
2609 - (BOOL)sourceList:(PXSourceList*)aSourceList isGroupAlwaysExpanded:(id)group
2610 {
2611     if ([[group identifier] isEqualToString:@"library"])
2612         return YES;
2613
2614     return NO;
2615 }
2616
2617 - (void)sourceListSelectionDidChange:(NSNotification *)notification
2618 {
2619     playlist_t * p_playlist = pl_Get( VLCIntf );
2620
2621     NSIndexSet *selectedIndexes = [o_sidebar_view selectedRowIndexes];
2622     id item = [o_sidebar_view itemAtRow:[selectedIndexes firstIndex]];
2623
2624
2625     //Set the label text to represent the new selection
2626     if ([item sdtype] > -1 && [[item identifier] length] > 0)
2627     {
2628         BOOL sd_loaded = playlist_IsServicesDiscoveryLoaded( p_playlist, [[item identifier] UTF8String] );
2629         if (!sd_loaded)
2630         {
2631             playlist_ServicesDiscoveryAdd( p_playlist, [[item identifier] UTF8String] );
2632         }
2633     }
2634
2635     [o_chosen_category_lbl setStringValue:[item title]];
2636
2637     if ([[item identifier] isEqualToString:@"playlist"])
2638     {
2639         [[[VLCMain sharedInstance] playlist] setPlaylistRoot:p_playlist->p_local_category];
2640     }
2641     else if([[item identifier] isEqualToString:@"medialibrary"])
2642     {
2643         [[[VLCMain sharedInstance] playlist] setPlaylistRoot:p_playlist->p_ml_category];
2644     }
2645     else
2646     {
2647         playlist_item_t * pl_item;
2648         PL_LOCK;
2649         pl_item = playlist_ChildSearchName( p_playlist->p_root, [[item untranslatedTitle] UTF8String] );
2650         PL_UNLOCK;
2651         [[[VLCMain sharedInstance] playlist] setPlaylistRoot: pl_item];
2652     }
2653
2654     PL_LOCK;
2655     if ([[[VLCMain sharedInstance] playlist] currentPlaylistRoot] != p_playlist->p_local_category || p_playlist->p_local_category->i_children > 0)
2656         [self hideDropZone];
2657     else
2658         [self showDropZone];
2659     PL_UNLOCK;
2660 }
2661
2662 - (NSDragOperation)sourceList:(PXSourceList *)aSourceList validateDrop:(id <NSDraggingInfo>)info proposedItem:(id)item proposedChildIndex:(NSInteger)index
2663 {
2664     if ([[item identifier] isEqualToString:@"playlist"] || [[item identifier] isEqualToString:@"medialibrary"] )
2665     {
2666         NSPasteboard *o_pasteboard = [info draggingPasteboard];
2667         if ([[o_pasteboard types] containsObject: @"VLCPlaylistItemPboardType"] || [[o_pasteboard types] containsObject: NSFilenamesPboardType])
2668             return NSDragOperationGeneric;
2669     }
2670     return NSDragOperationNone;
2671 }
2672
2673 - (BOOL)sourceList:(PXSourceList *)aSourceList acceptDrop:(id <NSDraggingInfo>)info item:(id)item childIndex:(NSInteger)index
2674 {
2675     NSPasteboard *o_pasteboard = [info draggingPasteboard];
2676
2677     playlist_t * p_playlist = pl_Get( VLCIntf );
2678     playlist_item_t *p_node;
2679
2680     if ([[item identifier] isEqualToString:@"playlist"])
2681         p_node = p_playlist->p_local_category;
2682     else
2683         p_node = p_playlist->p_ml_category;
2684
2685     if( [[o_pasteboard types] containsObject: NSFilenamesPboardType] )
2686     {
2687         NSArray *o_values = [[o_pasteboard propertyListForType: NSFilenamesPboardType] sortedArrayUsingSelector: @selector(caseInsensitiveCompare:)];
2688         NSUInteger count = [o_values count];
2689         NSMutableArray *o_array = [NSMutableArray arrayWithCapacity:count];
2690
2691         for( NSUInteger i = 0; i < count; i++)
2692         {
2693             NSDictionary *o_dic;
2694             char *psz_uri = make_URI([[o_values objectAtIndex:i] UTF8String], NULL);
2695             if( !psz_uri )
2696                 continue;
2697
2698             o_dic = [NSDictionary dictionaryWithObject:[NSString stringWithCString:psz_uri encoding:NSUTF8StringEncoding] forKey:@"ITEM_URL"];
2699
2700             free( psz_uri );
2701
2702             [o_array addObject: o_dic];
2703         }
2704
2705         [[[VLCMain sharedInstance] playlist] appendNodeArray:o_array inNode: p_node atPos:-1 enqueue:YES];
2706         return YES;
2707     }
2708     else if( [[o_pasteboard types] containsObject: @"VLCPlaylistItemPboardType"] )
2709     {
2710         NSArray * array = [[[VLCMain sharedInstance] playlist] draggedItems];
2711
2712         NSUInteger count = [array count];
2713         playlist_item_t * p_item = NULL;
2714
2715         PL_LOCK;
2716         for( NSUInteger i = 0; i < count; i++ )
2717         {
2718             p_item = [[array objectAtIndex:i] pointerValue];
2719             if( !p_item ) continue;
2720             playlist_NodeAddCopy( p_playlist, p_item, p_node, PLAYLIST_END );
2721         }
2722         PL_UNLOCK;
2723
2724         return YES;
2725     }
2726     return NO;
2727 }
2728
2729 - (id)sourceList:(PXSourceList *)aSourceList persistentObjectForItem:(id)item
2730 {
2731     return [item identifier];
2732 }
2733
2734 - (id)sourceList:(PXSourceList *)aSourceList itemForPersistentObject:(id)object
2735 {
2736     /* the following code assumes for sakes of simplicity that only the top level
2737      * items are allowed to have children */
2738
2739     NSArray * array = [NSArray arrayWithArray: o_sidebaritems]; // read-only arrays are noticebly faster
2740     NSUInteger count = [array count];
2741     if (count < 1)
2742         return nil;
2743
2744     for (NSUInteger x = 0; x < count; x++)
2745     {
2746         id item = [array objectAtIndex: x]; // save one objc selector call
2747         if ([[item identifier] isEqualToString:object])
2748             return item;
2749     }
2750
2751     return nil;
2752 }
2753
2754 #pragma mark -
2755 #pragma mark Accessibility stuff
2756
2757 - (NSArray *)accessibilityAttributeNames
2758 {
2759     if( !b_dark_interface )
2760         return [super accessibilityAttributeNames];
2761
2762     static NSMutableArray *attributes = nil;
2763     if ( attributes == nil ) {
2764         attributes = [[super accessibilityAttributeNames] mutableCopy];
2765         NSArray *appendAttributes = [NSArray arrayWithObjects: NSAccessibilitySubroleAttribute,
2766                                      NSAccessibilityCloseButtonAttribute,
2767                                      NSAccessibilityMinimizeButtonAttribute,
2768                                      NSAccessibilityZoomButtonAttribute,
2769                                      nil];
2770
2771         for( NSString *attribute in appendAttributes )
2772         {
2773             if( ![attributes containsObject:attribute] )
2774                 [attributes addObject:attribute];
2775         }
2776     }
2777     return attributes;
2778 }
2779
2780 - (id)accessibilityAttributeValue: (NSString*)o_attribute_name
2781 {
2782     if( b_dark_interface )
2783     {
2784         VLCMainWindowTitleView *o_tbv = o_titlebar_view;
2785
2786         if( [o_attribute_name isEqualTo: NSAccessibilitySubroleAttribute] )
2787             return NSAccessibilityStandardWindowSubrole;
2788
2789         if( [o_attribute_name isEqualTo: NSAccessibilityCloseButtonAttribute] )
2790             return [[o_tbv closeButton] cell];
2791
2792         if( [o_attribute_name isEqualTo: NSAccessibilityMinimizeButtonAttribute] )
2793             return [[o_tbv minimizeButton] cell];
2794         
2795         if( [o_attribute_name isEqualTo: NSAccessibilityZoomButtonAttribute] )
2796             return [[o_tbv zoomButton] cell];
2797     }
2798
2799     return [super accessibilityAttributeValue: o_attribute_name];
2800 }
2801
2802 - (id)detachedTitlebarView
2803 {
2804     return o_detached_titlebar_view;
2805 }
2806 @end
2807
2808 @implementation VLCDetachedVideoWindow
2809
2810 - (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)styleMask
2811                   backing:(NSBackingStoreType)backingType defer:(BOOL)flag
2812 {
2813     b_dark_interface = config_GetInt( VLCIntf, "macosx-interfacestyle" );
2814     b_video_deco = config_GetInt( VLCIntf, "video-deco" );
2815
2816     if (b_dark_interface || !b_video_deco)
2817     {
2818 #ifdef MAC_OS_X_VERSION_10_7
2819         if (OSX_LION)
2820             styleMask = NSBorderlessWindowMask | NSResizableWindowMask;
2821         else
2822             styleMask = NSBorderlessWindowMask;
2823 #else
2824         styleMask = NSBorderlessWindowMask;
2825 #endif
2826     }
2827
2828     self = [super initWithContentRect:contentRect styleMask:styleMask
2829                                   backing:backingType defer:flag];
2830
2831     /* we want to be moveable regardless of our style */
2832     [self setMovableByWindowBackground: YES];
2833
2834     /* we don't want this window to be restored on relaunch */
2835     if (OSX_LION)
2836         [self setRestorable:NO];
2837
2838     return self;
2839 }
2840
2841 - (void)awakeFromNib
2842 {
2843     [self setAcceptsMouseMovedEvents: YES];
2844
2845     if (b_dark_interface)
2846     {
2847         [self setBackgroundColor: [NSColor clearColor]];
2848         [self setOpaque: NO];
2849         [self display];
2850         [self setHasShadow:NO];
2851         [self setHasShadow:YES];
2852     }
2853 }
2854
2855 - (IBAction)fullscreen:(id)sender
2856 {
2857     [[VLCCoreInteraction sharedInstance] toggleFullscreen];
2858 }
2859
2860 - (BOOL)isFullscreen
2861 {
2862     return [[VLCMainWindow sharedInstance] isFullscreen];
2863 }
2864
2865 - (void)performClose:(id)sender
2866 {
2867     if (b_dark_interface || !b_video_deco)
2868         [[VLCMainWindow sharedInstance] performClose: sender];
2869     else
2870         [super performClose: sender];
2871 }
2872
2873 - (void)performMiniaturize:(id)sender
2874 {
2875     if (b_dark_interface || !b_video_deco)
2876         [self miniaturize: sender];
2877     else
2878         [super performMiniaturize: sender];
2879 }
2880
2881 - (void)performZoom:(id)sender
2882 {
2883     if (b_dark_interface || !b_video_deco)
2884         [self customZoom: sender];
2885     else
2886         [super performZoom: sender];
2887 }
2888
2889 - (void)zoom:(id)sender
2890 {
2891     if (b_dark_interface || !b_video_deco)
2892         [self customZoom: sender];
2893     else
2894         [super zoom: sender];
2895 }
2896
2897 - (BOOL)canBecomeKeyWindow
2898 {
2899     return YES;
2900 }
2901
2902 - (BOOL)validateMenuItem:(NSMenuItem *)menuItem
2903 {
2904     SEL s_menuAction = [menuItem action];
2905
2906     if ((s_menuAction == @selector(performClose:)) || (s_menuAction == @selector(performMiniaturize:)) || (s_menuAction == @selector(performZoom:)))
2907         return YES;
2908
2909     return [super validateMenuItem:menuItem];
2910 }
2911
2912 /**
2913  * Given a proposed frame rectangle, return a modified version
2914  * which will fit inside the screen.
2915  *
2916  * This method is based upon NSWindow.m, part of the GNUstep GUI Library, licensed under LGPLv2+.
2917  *    Authors:  Scott Christley <scottc@net-community.com>, Venkat Ajjanagadde <venkat@ocbi.com>,
2918  *              Felipe A. Rodriguez <far@ix.netcom.com>, Richard Frith-Macdonald <richard@brainstorm.co.uk>
2919  *    Copyright (C) 1996 Free Software Foundation, Inc.
2920  */
2921 - (NSRect) customConstrainFrameRect: (NSRect)frameRect toScreen: (NSScreen*)screen
2922 {
2923     NSRect screenRect = [screen visibleFrame];
2924     float difference;
2925
2926     /* Move top edge of the window inside the screen */
2927     difference = NSMaxY (frameRect) - NSMaxY (screenRect);
2928     if (difference > 0)
2929     {
2930         frameRect.origin.y -= difference;
2931     }
2932
2933     /* If the window is resizable, resize it (if needed) so that the
2934      bottom edge is on the screen or can be on the screen when the user moves
2935      the window */
2936     difference = NSMaxY (screenRect) - NSMaxY (frameRect);
2937     if (_styleMask & NSResizableWindowMask)
2938     {
2939         float difference2;
2940
2941         difference2 = screenRect.origin.y - frameRect.origin.y;
2942         difference2 -= difference;
2943         // Take in account the space between the top of window and the top of the
2944         // screen which can be used to move the bottom of the window on the screen
2945         if (difference2 > 0)
2946         {
2947             frameRect.size.height -= difference2;
2948             frameRect.origin.y += difference2;
2949         }
2950
2951         /* Ensure that resizing doesn't makewindow smaller than minimum */
2952         difference2 = [self minSize].height - frameRect.size.height;
2953         if (difference2 > 0)
2954         {
2955             frameRect.size.height += difference2;
2956             frameRect.origin.y -= difference2;
2957         }
2958     }
2959
2960     return frameRect;
2961 }
2962
2963 #define DIST 3
2964
2965 /**
2966  Zooms the receiver.   This method calls the delegate method
2967  windowShouldZoom:toFrame: to determine if the window should
2968  be allowed to zoom to full screen.
2969  *
2970  * This method is based upon NSWindow.m, part of the GNUstep GUI Library, licensed under LGPLv2+.
2971  *    Authors:  Scott Christley <scottc@net-community.com>, Venkat Ajjanagadde <venkat@ocbi.com>,
2972  *              Felipe A. Rodriguez <far@ix.netcom.com>, Richard Frith-Macdonald <richard@brainstorm.co.uk>
2973  *    Copyright (C) 1996 Free Software Foundation, Inc.
2974  */
2975 - (void) customZoom: (id)sender
2976 {
2977     NSRect maxRect = [[self screen] visibleFrame];
2978     NSRect currentFrame = [self frame];
2979
2980     if ([[self delegate] respondsToSelector: @selector(windowWillUseStandardFrame:defaultFrame:)])
2981     {
2982         maxRect = [[self delegate] windowWillUseStandardFrame: self defaultFrame: maxRect];
2983     }
2984
2985     maxRect = [self customConstrainFrameRect: maxRect toScreen: [self screen]];
2986
2987     // Compare the new frame with the current one
2988     if ((abs(NSMaxX(maxRect) - NSMaxX(currentFrame)) < DIST)
2989         && (abs(NSMaxY(maxRect) - NSMaxY(currentFrame)) < DIST)
2990         && (abs(NSMinX(maxRect) - NSMinX(currentFrame)) < DIST)
2991         && (abs(NSMinY(maxRect) - NSMinY(currentFrame)) < DIST))
2992     {
2993         // Already in zoomed mode, reset user frame, if stored
2994         if ([self frameAutosaveName] != nil)
2995         {
2996             [self setFrame: previousSavedFrame display: YES animate: YES];
2997             [self saveFrameUsingName: [self frameAutosaveName]];
2998         }
2999         return;
3000     }
3001
3002     if ([self frameAutosaveName] != nil)
3003     {
3004         [self saveFrameUsingName: [self frameAutosaveName]];
3005         previousSavedFrame = [self frame];
3006     }
3007
3008     [self setFrame: maxRect display: YES animate: YES];
3009 }
3010
3011 - (NSArray *)accessibilityAttributeNames
3012 {
3013     if( !b_dark_interface )
3014         return [super accessibilityAttributeNames];
3015     
3016     static NSMutableArray *attributes = nil;
3017     if ( attributes == nil ) {
3018         attributes = [[super accessibilityAttributeNames] mutableCopy];
3019         NSArray *appendAttributes = [NSArray arrayWithObjects: NSAccessibilitySubroleAttribute,
3020                                      NSAccessibilityCloseButtonAttribute,
3021                                      NSAccessibilityMinimizeButtonAttribute,
3022                                      NSAccessibilityZoomButtonAttribute,
3023                                      nil];
3024         
3025         for( NSString *attribute in appendAttributes )
3026         {
3027             if( ![attributes containsObject:attribute] )
3028                 [attributes addObject:attribute];
3029         }
3030     }
3031     return attributes;
3032 }
3033
3034 - (id)accessibilityAttributeValue: (NSString*)o_attribute_name
3035 {
3036     if( b_dark_interface )
3037     {
3038         VLCMainWindowTitleView *o_tbv = [[VLCMainWindow sharedInstance] detachedTitlebarView];
3039         
3040         if( [o_attribute_name isEqualTo: NSAccessibilitySubroleAttribute] )
3041             return NSAccessibilityStandardWindowSubrole;
3042         
3043         if( [o_attribute_name isEqualTo: NSAccessibilityCloseButtonAttribute] )
3044             return [[o_tbv closeButton] cell];
3045         
3046         if( [o_attribute_name isEqualTo: NSAccessibilityMinimizeButtonAttribute] )
3047             return [[o_tbv minimizeButton] cell];
3048         
3049         if( [o_attribute_name isEqualTo: NSAccessibilityZoomButtonAttribute] )
3050             return [[o_tbv zoomButton] cell];
3051     }
3052     
3053     return [super accessibilityAttributeValue: o_attribute_name];
3054 }
3055
3056 @end