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