1 /*****************************************************************************
2 * MainWindow.m: MacOS X interface module
3 *****************************************************************************
4 * Copyright (C) 2002-2012 VLC authors and VideoLAN
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>
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.
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.
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 *****************************************************************************/
27 #import "CompatibilityFixes.h"
28 #import "MainWindow.h"
30 #import "CoreInteraction.h"
31 #import "AudioEffects.h"
34 #import "controls.h" // TODO: remove me
36 #import "SideBarItem.h"
38 #import <vlc_playlist.h>
39 #import <vlc_aout_intf.h>
41 #import <vlc_strings.h>
42 #import <vlc_services_discovery.h>
43 #import <vlc_aout_intf.h>
45 @interface VLCMainWindow ()
46 - (void)addJumpButtons:(BOOL)b_fast;
47 - (void)removeJumpButtons:(BOOL)b_fast;
48 - (void)addPlaymodeButtons:(BOOL)b_fast;
49 - (void)removePlaymodeButtons:(BOOL)b_fast;
51 - (void)resetPreviousButton;
52 - (void)resetBackwardSkip;
53 - (void)resetNextButton;
54 - (void)resetForwardSkip;
55 - (void)resizePlaylistAfterCollapse;
56 - (void)makeSplitViewVisible;
57 - (void)makeSplitViewHidden;
59 - (NSRect)customConstrainFrameRect: (NSRect)frameRect toScreen: (NSScreen*)screen;
62 @implementation VLCMainWindow
63 static const float f_min_video_height = 70.0;
65 static VLCMainWindow *_o_sharedInstance = nil;
67 + (VLCMainWindow *)sharedInstance
69 return _o_sharedInstance ? _o_sharedInstance : [[self alloc] init];
73 #pragma mark Initialization
77 if( _o_sharedInstance )
80 return _o_sharedInstance;
84 _o_sharedInstance = [super init];
87 return _o_sharedInstance;
90 - (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)styleMask
91 backing:(NSBackingStoreType)backingType defer:(BOOL)flag
93 b_dark_interface = config_GetInt( VLCIntf, "macosx-interfacestyle" );
97 #ifdef MAC_OS_X_VERSION_10_7
99 styleMask = NSBorderlessWindowMask | NSResizableWindowMask;
101 styleMask = NSBorderlessWindowMask;
103 styleMask = NSBorderlessWindowMask;
107 self = [super initWithContentRect:contentRect styleMask:styleMask
108 backing:backingType defer:flag];
109 _o_sharedInstance = self;
111 [[VLCMain sharedInstance] updateTogglePlaylistState];
113 /* we want to be moveable regardless of our style */
114 [self setMovableByWindowBackground: YES];
116 /* we don't want this window to be restored on relaunch */
118 [self setRestorable:NO];
123 - (BOOL)isEvent:(NSEvent *)o_event forKey:(const char *)keyString
128 key = config_GetPsz( VLCIntf, keyString );
129 o_key = [NSString stringWithFormat:@"%s", key];
132 unsigned int i_keyModifiers = [[VLCStringUtility sharedInstance] VLCModifiersToCocoa:o_key];
134 NSString * characters = [o_event charactersIgnoringModifiers];
135 if ([characters length] > 0) {
136 return [[characters lowercaseString] isEqualToString: [[VLCStringUtility sharedInstance] VLCKeyToString: o_key]] &&
137 (i_keyModifiers & NSShiftKeyMask) == ([o_event modifierFlags] & NSShiftKeyMask) &&
138 (i_keyModifiers & NSControlKeyMask) == ([o_event modifierFlags] & NSControlKeyMask) &&
139 (i_keyModifiers & NSAlternateKeyMask) == ([o_event modifierFlags] & NSAlternateKeyMask) &&
140 (i_keyModifiers & NSCommandKeyMask) == ([o_event modifierFlags] & NSCommandKeyMask);
145 - (BOOL)performKeyEquivalent:(NSEvent *)o_event
148 // these are key events which should be handled by vlc core, but are attached to a main menu item
149 if( ![self isEvent: o_event forKey: "key-vol-up"] &&
150 ![self isEvent: o_event forKey: "key-vol-down"] &&
151 ![self isEvent: o_event forKey: "key-vol-mute"] )
153 /* We indeed want to prioritize some Cocoa key equivalent against libvlc,
154 so we perform the menu equivalent now. */
155 if([[NSApp mainMenu] performKeyEquivalent:o_event])
161 return [[VLCMain sharedInstance] hasDefinedShortcutKey:o_event force:b_force] ||
162 [(VLCControls *)[[VLCMain sharedInstance] controls] keyEvent:o_event];
167 if (b_dark_interface)
168 [o_color_backdrop release];
170 [[NSNotificationCenter defaultCenter] removeObserver: self];
171 [o_sidebaritems release];
173 if( o_extra_video_window )
175 [o_extra_video_window release];
176 o_extra_video_window = nil;
184 BOOL b_splitviewShouldBeHidden = NO;
186 /* setup the styled interface */
187 b_video_deco = var_InheritBool( VLCIntf, "video-deco" );
188 b_nativeFullscreenMode = NO;
189 #ifdef MAC_OS_X_VERSION_10_7
190 if( OSX_LION && b_video_deco )
191 b_nativeFullscreenMode = var_InheritBool( VLCIntf, "macosx-nativefullscreenmode" );
193 t_hide_mouse_timer = nil;
194 [o_detached_video_window setDelegate: self];
195 [self useOptimizedDrawing: YES];
197 [o_play_btn setToolTip: _NS("Play/Pause")];
198 [[o_play_btn cell] accessibilitySetOverrideValue:_NS("Click to play or pause the current media.") forAttribute:NSAccessibilityDescriptionAttribute];
199 [o_detached_play_btn setToolTip: [o_play_btn toolTip]];
200 [[o_play_btn cell] accessibilitySetOverrideValue:[o_play_btn toolTip] forAttribute:NSAccessibilityTitleAttribute];
201 [[o_detached_play_btn cell] accessibilitySetOverrideValue:[o_play_btn toolTip] forAttribute:NSAccessibilityTitleAttribute];
202 [[o_detached_play_btn cell] accessibilitySetOverrideValue:_NS("Click to play or pause the current media.") forAttribute:NSAccessibilityDescriptionAttribute];
203 [o_bwd_btn setToolTip: _NS("Backward")];
204 [[o_bwd_btn cell] accessibilitySetOverrideValue:_NS("Click to go to the previous playlist item. Hold to skip backward through the current media.") forAttribute:NSAccessibilityDescriptionAttribute];
205 [o_detached_bwd_btn setToolTip: [o_bwd_btn toolTip]];
206 [[o_bwd_btn cell] accessibilitySetOverrideValue:[o_bwd_btn toolTip] forAttribute:NSAccessibilityTitleAttribute];
207 [[o_detached_bwd_btn cell] accessibilitySetOverrideValue:[o_bwd_btn toolTip] forAttribute:NSAccessibilityTitleAttribute];
208 [[o_detached_bwd_btn cell] accessibilitySetOverrideValue:_NS("Click to go to the previous playlist item. Hold to skip backward through the current media.") forAttribute:NSAccessibilityDescriptionAttribute];
209 [o_fwd_btn setToolTip: _NS("Forward")];
210 [[o_fwd_btn cell] accessibilitySetOverrideValue:_NS("Click to go to the next playlist item. Hold to skip forward through the current media.") forAttribute:NSAccessibilityDescriptionAttribute];
211 [o_detached_fwd_btn setToolTip: [o_fwd_btn toolTip]];
212 [[o_detached_fwd_btn cell] accessibilitySetOverrideValue:[o_fwd_btn toolTip] forAttribute:NSAccessibilityTitleAttribute];
213 [[o_detached_fwd_btn cell] accessibilitySetOverrideValue:[o_fwd_btn toolTip] forAttribute:NSAccessibilityTitleAttribute];
214 [[o_detached_fwd_btn cell] accessibilitySetOverrideValue:_NS("Click to go to the next playlist item. Hold to skip forward through the current media.") forAttribute:NSAccessibilityDescriptionAttribute];
215 [o_stop_btn setToolTip: _NS("Stop")];
216 [[o_stop_btn cell] accessibilitySetOverrideValue:_NS("Click to stop playback.") forAttribute:NSAccessibilityDescriptionAttribute];
217 [[o_stop_btn cell] accessibilitySetOverrideValue:[o_stop_btn toolTip] forAttribute:NSAccessibilityTitleAttribute];
218 [o_playlist_btn setToolTip: _NS("Show/Hide Playlist")];
219 [[o_playlist_btn cell] accessibilitySetOverrideValue:_NS("Click to switch between video output and playlist. If no video is shown in the main window, this allows you to hide the playlist.") forAttribute:NSAccessibilityDescriptionAttribute];
220 [[o_playlist_btn cell] accessibilitySetOverrideValue:[o_playlist_btn toolTip] forAttribute:NSAccessibilityTitleAttribute];
221 [o_repeat_btn setToolTip: _NS("Repeat")];
222 [[o_repeat_btn cell] accessibilitySetOverrideValue:_NS("Click to change repeat mode. There are 3 states: repeat one, repeat all and off.") forAttribute:NSAccessibilityDescriptionAttribute];
223 [[o_repeat_btn cell] accessibilitySetOverrideValue:[o_repeat_btn toolTip] forAttribute:NSAccessibilityTitleAttribute];
224 [o_shuffle_btn setToolTip: _NS("Shuffle")];
225 [[o_shuffle_btn cell] accessibilitySetOverrideValue:[o_shuffle_btn toolTip] forAttribute:NSAccessibilityTitleAttribute];
226 [[o_shuffle_btn cell] accessibilitySetOverrideValue:_NS("Click to enable or disable random playback.") forAttribute:NSAccessibilityDescriptionAttribute];
227 [o_effects_btn setToolTip: _NS("Effects")];
228 [[o_effects_btn cell] accessibilitySetOverrideValue:_NS("Click to show an Audio Effects panel featuring an equalizer and further filters.") forAttribute:NSAccessibilityDescriptionAttribute];
229 [[o_effects_btn cell] accessibilitySetOverrideValue:[o_effects_btn toolTip] forAttribute:NSAccessibilityTitleAttribute];
230 [o_fullscreen_btn setToolTip: _NS("Toggle Fullscreen mode")];
231 [[o_fullscreen_btn cell] accessibilitySetOverrideValue:_NS("Click to enable fullscreen video playback.") forAttribute:NSAccessibilityDescriptionAttribute];
232 [o_detached_fullscreen_btn setToolTip: [o_fullscreen_btn toolTip]];
233 [[o_fullscreen_btn cell] accessibilitySetOverrideValue:[o_fullscreen_btn toolTip] forAttribute:NSAccessibilityTitleAttribute];
234 [[o_detached_fullscreen_btn cell] accessibilitySetOverrideValue:[o_fullscreen_btn toolTip] forAttribute:NSAccessibilityTitleAttribute];
235 [[o_detached_fullscreen_btn cell] accessibilitySetOverrideValue:_NS("Click to enable fullscreen video playback.") forAttribute:NSAccessibilityDescriptionAttribute];
236 [[o_search_fld cell] setPlaceholderString: _NS("Search")];
237 [[o_search_fld cell] accessibilitySetOverrideValue:_NS("Enter a term to search the playlist. Results will be selected in the table.") forAttribute:NSAccessibilityDescriptionAttribute];
238 [o_volume_sld setToolTip: _NS("Volume")];
239 [[o_volume_sld cell] accessibilitySetOverrideValue:_NS("Click and move the mouse while keeping the button pressed to use this slider to change the volume.") forAttribute:NSAccessibilityDescriptionAttribute];
240 [[o_volume_sld cell] accessibilitySetOverrideValue:[o_volume_sld toolTip] forAttribute:NSAccessibilityTitleAttribute];
241 [o_volume_down_btn setToolTip: _NS("Mute")];
242 [[o_volume_down_btn cell] accessibilitySetOverrideValue:_NS("Click to mute or unmute the audio.") forAttribute:NSAccessibilityDescriptionAttribute];
243 [[o_volume_down_btn cell] accessibilitySetOverrideValue:[o_volume_down_btn toolTip] forAttribute:NSAccessibilityTitleAttribute];
244 [o_volume_up_btn setToolTip: _NS("Full Volume")];
245 [[o_volume_up_btn cell] accessibilitySetOverrideValue:_NS("Click to play the audio at maximum volume.") forAttribute:NSAccessibilityDescriptionAttribute];
246 [[o_volume_up_btn cell] accessibilitySetOverrideValue:[o_volume_up_btn toolTip] forAttribute:NSAccessibilityTitleAttribute];
247 [o_time_sld setToolTip: _NS("Position")];
248 [[o_time_sld cell] accessibilitySetOverrideValue:_NS("Click and move the mouse while keeping the button pressed to use this slider to change current playback position.") forAttribute:NSAccessibilityDescriptionAttribute];
249 [[o_time_sld cell] accessibilitySetOverrideValue:[o_time_sld toolTip] forAttribute:NSAccessibilityTitleAttribute];
250 [o_detached_time_sld setToolTip: [o_time_sld toolTip]];
251 [[o_detached_time_sld cell] accessibilitySetOverrideValue:_NS("Click and move the mouse while keeping the button pressed to use this slider to change current playback position.") forAttribute:NSAccessibilityDescriptionAttribute];
252 [[o_detached_time_sld cell] accessibilitySetOverrideValue:[o_time_sld toolTip] forAttribute:NSAccessibilityTitleAttribute];
253 [o_dropzone_btn setTitle: _NS("Open media...")];
254 [[o_dropzone_btn cell] accessibilitySetOverrideValue:_NS("Click to open an advanced dialog to select the media to play. You can also drop files here to play.") forAttribute:NSAccessibilityDescriptionAttribute];
255 [o_dropzone_lbl setStringValue: _NS("Drop media here")];
257 if (!b_dark_interface) {
258 [o_bottombar_view setImagesLeft: [NSImage imageNamed:@"bottom-background"] middle: [NSImage imageNamed:@"bottom-background"] right: [NSImage imageNamed:@"bottom-background"]];
259 [o_detached_bottombar_view setImagesLeft: [NSImage imageNamed:@"bottom-background"] middle: [NSImage imageNamed:@"bottom-background"] right: [NSImage imageNamed:@"bottom-background"]];
260 [o_bwd_btn setImage: [NSImage imageNamed:@"back"]];
261 [o_bwd_btn setAlternateImage: [NSImage imageNamed:@"back-pressed"]];
262 [o_detached_bwd_btn setImage: [NSImage imageNamed:@"back"]];
263 [o_detached_bwd_btn setAlternateImage: [NSImage imageNamed:@"back-pressed"]];
264 o_play_img = [[NSImage imageNamed:@"play"] retain];
265 o_play_pressed_img = [[NSImage imageNamed:@"play-pressed"] retain];
266 o_pause_img = [[NSImage imageNamed:@"pause"] retain];
267 o_pause_pressed_img = [[NSImage imageNamed:@"pause-pressed"] retain];
268 [o_fwd_btn setImage: [NSImage imageNamed:@"forward"]];
269 [o_fwd_btn setAlternateImage: [NSImage imageNamed:@"forward-pressed"]];
270 [o_detached_fwd_btn setImage: [NSImage imageNamed:@"forward"]];
271 [o_detached_fwd_btn setAlternateImage: [NSImage imageNamed:@"forward-pressed"]];
272 [o_stop_btn setImage: [NSImage imageNamed:@"stop"]];
273 [o_stop_btn setAlternateImage: [NSImage imageNamed:@"stop-pressed"]];
274 [o_playlist_btn setImage: [NSImage imageNamed:@"playlist-btn"]];
275 [o_playlist_btn setAlternateImage: [NSImage imageNamed:@"playlist-btn-pressed"]];
276 o_repeat_img = [[NSImage imageNamed:@"repeat"] retain];
277 o_repeat_pressed_img = [[NSImage imageNamed:@"repeat-pressed"] retain];
278 o_repeat_all_img = [[NSImage imageNamed:@"repeat-all"] retain];
279 o_repeat_all_pressed_img = [[NSImage imageNamed:@"repeat-all-pressed"] retain];
280 o_repeat_one_img = [[NSImage imageNamed:@"repeat-one"] retain];
281 o_repeat_one_pressed_img = [[NSImage imageNamed:@"repeat-one-pressed"] retain];
282 o_shuffle_img = [[NSImage imageNamed:@"shuffle"] retain];
283 o_shuffle_pressed_img = [[NSImage imageNamed:@"shuffle-pressed"] retain];
284 o_shuffle_on_img = [[NSImage imageNamed:@"shuffle-blue"] retain];
285 o_shuffle_on_pressed_img = [[NSImage imageNamed:@"shuffle-blue-pressed"] retain];
286 [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"]];
287 [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"]];
288 [o_volume_down_btn setImage: [NSImage imageNamed:@"volume-low"]];
289 [o_volume_track_view setImage: [NSImage imageNamed:@"volume-slider-track"]];
290 [o_volume_up_btn setImage: [NSImage imageNamed:@"volume-high"]];
291 if (b_nativeFullscreenMode)
293 [o_effects_btn setImage: [NSImage imageNamed:@"effects-one-button"]];
294 [o_effects_btn setAlternateImage: [NSImage imageNamed:@"effects-one-button-blue"]];
298 [o_effects_btn setImage: [NSImage imageNamed:@"effects-double-buttons"]];
299 [o_effects_btn setAlternateImage: [NSImage imageNamed:@"effects-double-buttons-pressed"]];
301 [o_fullscreen_btn setImage: [NSImage imageNamed:@"fullscreen-double-buttons"]];
302 [o_fullscreen_btn setAlternateImage: [NSImage imageNamed:@"fullscreen-double-buttons-pressed"]];
303 [o_detached_fullscreen_btn setImage: [NSImage imageNamed:@"fullscreen-one-button"]];
304 [o_detached_fullscreen_btn setAlternateImage: [NSImage imageNamed:@"fullscreen-one-button-pressed"]];
305 [o_time_sld_fancygradient_view setImagesLeft:[NSImage imageNamed:@"progression-fill-left"] middle:[NSImage imageNamed:@"progression-fill-middle"] right:[NSImage imageNamed:@"progression-fill-right"]];
306 [o_detached_time_sld_fancygradient_view setImagesLeft:[NSImage imageNamed:@"progression-fill-left"] middle:[NSImage imageNamed:@"progression-fill-middle"] right:[NSImage imageNamed:@"progression-fill-right"]];
310 [o_bottombar_view setImagesLeft: [NSImage imageNamed:@"bottomdark-left"] middle: [NSImage imageNamed:@"bottom-background_dark"] right: [NSImage imageNamed:@"bottomdark-right"]];
311 [o_detached_bottombar_view setImagesLeft: [NSImage imageNamed:@"bottomdark-left"] middle: [NSImage imageNamed:@"bottom-background_dark"] right: [NSImage imageNamed:@"bottomdark-right"]];
312 [o_bwd_btn setImage: [NSImage imageNamed:@"back_dark"]];
313 [o_bwd_btn setAlternateImage: [NSImage imageNamed:@"back-pressed_dark"]];
314 [o_detached_bwd_btn setImage: [NSImage imageNamed:@"back_dark"]];
315 [o_detached_bwd_btn setAlternateImage: [NSImage imageNamed:@"back-pressed_dark"]];
316 o_play_img = [[NSImage imageNamed:@"play_dark"] retain];
317 o_play_pressed_img = [[NSImage imageNamed:@"play-pressed_dark"] retain];
318 o_pause_img = [[NSImage imageNamed:@"pause_dark"] retain];
319 o_pause_pressed_img = [[NSImage imageNamed:@"pause-pressed_dark"] retain];
320 [o_fwd_btn setImage: [NSImage imageNamed:@"forward_dark"]];
321 [o_fwd_btn setAlternateImage: [NSImage imageNamed:@"forward-pressed_dark"]];
322 [o_detached_fwd_btn setImage: [NSImage imageNamed:@"forward_dark"]];
323 [o_detached_fwd_btn setAlternateImage: [NSImage imageNamed:@"forward-pressed_dark"]];
324 [o_stop_btn setImage: [NSImage imageNamed:@"stop_dark"]];
325 [o_stop_btn setAlternateImage: [NSImage imageNamed:@"stop-pressed_dark"]];
326 [o_playlist_btn setImage: [NSImage imageNamed:@"playlist_dark"]];
327 [o_playlist_btn setAlternateImage: [NSImage imageNamed:@"playlist-pressed_dark"]];
328 o_repeat_img = [[NSImage imageNamed:@"repeat_dark"] retain];
329 o_repeat_pressed_img = [[NSImage imageNamed:@"repeat-pressed_dark"] retain];
330 o_repeat_all_img = [[NSImage imageNamed:@"repeat-all-blue_dark"] retain];
331 o_repeat_all_pressed_img = [[NSImage imageNamed:@"repeat-all-blue-pressed_dark"] retain];
332 o_repeat_one_img = [[NSImage imageNamed:@"repeat-one-blue_dark"] retain];
333 o_repeat_one_pressed_img = [[NSImage imageNamed:@"repeat-one-blue-pressed_dark"] retain];
334 o_shuffle_img = [[NSImage imageNamed:@"shuffle_dark"] retain];
335 o_shuffle_pressed_img = [[NSImage imageNamed:@"shuffle-pressed_dark"] retain];
336 o_shuffle_on_img = [[NSImage imageNamed:@"shuffle-blue_dark"] retain];
337 o_shuffle_on_pressed_img = [[NSImage imageNamed:@"shuffle-blue-pressed_dark"] retain];
338 [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"]];
339 [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"]];
340 [o_volume_down_btn setImage: [NSImage imageNamed:@"volume-low_dark"]];
341 [o_volume_track_view setImage: [NSImage imageNamed:@"volume-slider-track_dark"]];
342 [o_volume_up_btn setImage: [NSImage imageNamed:@"volume-high_dark"]];
343 if (b_nativeFullscreenMode)
345 [o_effects_btn setImage: [NSImage imageNamed:@"effects-one-button_dark"]];
346 [o_effects_btn setAlternateImage: [NSImage imageNamed:@"effects-one-button-blue_dark"]];
350 [o_effects_btn setImage: [NSImage imageNamed:@"effects-double-buttons_dark"]];
351 [o_effects_btn setAlternateImage: [NSImage imageNamed:@"effects-double-buttons-pressed_dark"]];
353 [o_fullscreen_btn setImage: [NSImage imageNamed:@"fullscreen-double-buttons_dark"]];
354 [o_fullscreen_btn setAlternateImage: [NSImage imageNamed:@"fullscreen-double-buttons-pressed_dark"]];
355 [o_detached_fullscreen_btn setImage: [NSImage imageNamed:@"fullscreen-one-button_dark"]];
356 [o_detached_fullscreen_btn setAlternateImage: [NSImage imageNamed:@"fullscreen-one-button-pressed_dark"]];
357 [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"]];
358 [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"]];
360 [o_repeat_btn setImage: o_repeat_img];
361 [o_repeat_btn setAlternateImage: o_repeat_pressed_img];
362 [o_shuffle_btn setImage: o_shuffle_img];
363 [o_shuffle_btn setAlternateImage: o_shuffle_pressed_img];
364 [o_play_btn setImage: o_play_img];
365 [o_play_btn setAlternateImage: o_play_pressed_img];
366 [o_detached_play_btn setImage: o_play_img];
367 [o_detached_play_btn setAlternateImage: o_play_pressed_img];
368 BOOL b_mute = ![[VLCCoreInteraction sharedInstance] mute];
369 [o_volume_sld setEnabled: b_mute];
370 [o_volume_up_btn setEnabled: b_mute];
372 b_show_jump_buttons = config_GetInt( VLCIntf, "macosx-show-playback-buttons" );
373 if (b_show_jump_buttons)
374 [self addJumpButtons:YES];
376 b_show_playmode_buttons = config_GetInt( VLCIntf, "macosx-show-playmode-buttons" );
377 if (!b_show_playmode_buttons)
378 [self removePlaymodeButtons:YES];
380 /* interface builder action */
381 float f_threshold_height = f_min_video_height + [o_bottombar_view frame].size.height;
382 if( b_dark_interface )
383 f_threshold_height += [o_titlebar_view frame].size.height;
384 if( [[self contentView] frame].size.height < f_threshold_height )
385 b_splitviewShouldBeHidden = YES;
387 [self setDelegate: self];
388 [self setExcludedFromWindowsMenu: YES];
389 [self setAcceptsMouseMovedEvents: YES];
390 // Set that here as IB seems to be buggy
391 if (b_dark_interface && b_video_deco)
393 [self setContentMinSize:NSMakeSize(604., 288. + [o_titlebar_view frame].size.height)];
394 [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 )];
396 else if( b_video_deco )
398 [self setContentMinSize:NSMakeSize(604., 288.)];
399 [o_detached_video_window setContentMinSize: NSMakeSize( 363., f_min_video_height + [o_detached_bottombar_view frame].size.height )];
403 if (b_dark_interface)
404 [self setContentMinSize:NSMakeSize(604., 288. + [o_titlebar_view frame].size.height)];
406 [self setContentMinSize:NSMakeSize(604., 288.)];
408 [o_detached_bottombar_view setHidden:YES];
409 [o_detached_video_window setContentMinSize: NSMakeSize( f_min_video_height, f_min_video_height )];
412 [self setTitle: _NS("VLC media player")];
413 [o_time_fld setAlignment: NSCenterTextAlignment];
414 [o_time_fld setNeedsDisplay:YES];
415 b_dropzone_active = YES;
416 o_temp_view = [[NSView alloc] init];
417 [o_temp_view setAutoresizingMask:NSViewHeightSizable | NSViewWidthSizable];
418 [o_dropzone_view setFrame: [o_playlist_table frame]];
419 [o_left_split_view setFrame: [o_sidebar_view frame]];
420 if (b_nativeFullscreenMode)
423 [self setCollectionBehavior: NSWindowCollectionBehaviorFullScreenPrimary];
424 float f_width = [o_fullscreen_btn frame].size.width;
426 #define moveItem( item ) \
427 frame = [item frame]; \
428 frame.origin.x = f_width + frame.origin.x; \
429 [item setFrame: frame]
431 moveItem( o_effects_btn );
432 moveItem( o_volume_up_btn );
433 moveItem( o_volume_sld );
434 moveItem( o_volume_track_view );
435 moveItem( o_volume_down_btn );
436 moveItem( o_time_fld );
439 #define enlargeItem( item ) \
440 frame = [item frame]; \
441 frame.size.width = f_width + frame.size.width; \
442 [item setFrame: frame]
444 enlargeItem( o_time_sld );
445 enlargeItem( o_progress_bar );
446 enlargeItem( o_time_sld_background );
447 enlargeItem( o_time_sld_fancygradient_view );
450 [o_fullscreen_btn removeFromSuperviewWithoutNeedingDisplay];
454 [o_titlebar_view setFullscreenButtonHidden: YES];
456 [o_detached_titlebar_view setFullscreenButtonHidden: YES];
461 /* the default small size of the search field is slightly different on Lion, let's work-around that */
463 frame = [o_search_fld frame];
464 frame.origin.y = frame.origin.y + 2.0;
465 frame.size.height = frame.size.height - 1.0;
466 [o_search_fld setFrame: frame];
469 /* create the sidebar */
470 o_sidebaritems = [[NSMutableArray alloc] init];
471 SideBarItem *libraryItem = [SideBarItem itemWithTitle:_NS("LIBRARY") identifier:@"library"];
472 SideBarItem *playlistItem = [SideBarItem itemWithTitle:_NS("Playlist") identifier:@"playlist"];
473 [playlistItem setIcon: [NSImage imageNamed:@"sidebar-playlist"]];
474 SideBarItem *medialibraryItem = [SideBarItem itemWithTitle:_NS("Media Library") identifier:@"medialibrary"];
475 [medialibraryItem setIcon: [NSImage imageNamed:@"sidebar-playlist"]];
476 SideBarItem *mycompItem = [SideBarItem itemWithTitle:_NS("MY COMPUTER") identifier:@"mycomputer"];
477 SideBarItem *devicesItem = [SideBarItem itemWithTitle:_NS("DEVICES") identifier:@"devices"];
478 SideBarItem *lanItem = [SideBarItem itemWithTitle:_NS("LOCAL NETWORK") identifier:@"localnetwork"];
479 SideBarItem *internetItem = [SideBarItem itemWithTitle:_NS("INTERNET") identifier:@"internet"];
481 /* SD subnodes, inspired by the Qt4 intf */
482 char **ppsz_longnames;
484 char **ppsz_names = vlc_sd_GetNames( pl_Get( VLCIntf ), &ppsz_longnames, &p_categories );
486 msg_Err( VLCIntf, "no sd item found" ); //TODO
487 char **ppsz_name = ppsz_names, **ppsz_longname = ppsz_longnames;
488 int *p_category = p_categories;
489 NSMutableArray *internetItems = [[NSMutableArray alloc] init];
490 NSMutableArray *devicesItems = [[NSMutableArray alloc] init];
491 NSMutableArray *lanItems = [[NSMutableArray alloc] init];
492 NSMutableArray *mycompItems = [[NSMutableArray alloc] init];
493 NSString *o_identifier;
494 for (; *ppsz_name; ppsz_name++, ppsz_longname++, p_category++)
496 o_identifier = [NSString stringWithCString: *ppsz_name encoding: NSUTF8StringEncoding];
497 switch (*p_category) {
498 case SD_CAT_INTERNET:
500 [internetItems addObject: [SideBarItem itemWithTitle: _NS(*ppsz_longname) identifier: o_identifier]];
501 if (!strncmp( *ppsz_name, "podcast", 7 ))
502 [internetItems removeLastObject]; // we don't support podcasts at this point (see #6017)
503 // [[internetItems lastObject] setIcon: [NSImage imageNamed:@"sidebar-podcast"]];
505 [[internetItems lastObject] setIcon: [NSImage imageNamed:@"NSApplicationIcon"]];
506 [[internetItems lastObject] setSdtype: SD_CAT_INTERNET];
507 [[internetItems lastObject] setUntranslatedTitle: [NSString stringWithUTF8String: *ppsz_longname]];
512 [devicesItems addObject: [SideBarItem itemWithTitle: _NS(*ppsz_longname) identifier: o_identifier]];
513 [[devicesItems lastObject] setIcon: [NSImage imageNamed:@"NSApplicationIcon"]];
514 [[devicesItems lastObject] setSdtype: SD_CAT_DEVICES];
515 [[devicesItems lastObject] setUntranslatedTitle: [NSString stringWithUTF8String: *ppsz_longname]];
520 [lanItems addObject: [SideBarItem itemWithTitle: _NS(*ppsz_longname) identifier: o_identifier]];
521 [[lanItems lastObject] setIcon: [NSImage imageNamed:@"sidebar-local"]];
522 [[lanItems lastObject] setSdtype: SD_CAT_LAN];
523 [[lanItems lastObject] setUntranslatedTitle: [NSString stringWithUTF8String: *ppsz_longname]];
526 case SD_CAT_MYCOMPUTER:
528 [mycompItems addObject: [SideBarItem itemWithTitle: _NS(*ppsz_longname) identifier: o_identifier]];
529 if (!strncmp( *ppsz_name, "video_dir", 9 ))
530 [[mycompItems lastObject] setIcon: [NSImage imageNamed:@"sidebar-movie"]];
531 else if (!strncmp( *ppsz_name, "audio_dir", 9 ))
532 [[mycompItems lastObject] setIcon: [NSImage imageNamed:@"sidebar-music"]];
533 else if (!strncmp( *ppsz_name, "picture_dir", 11 ))
534 [[mycompItems lastObject] setIcon: [NSImage imageNamed:@"sidebar-pictures"]];
536 [[mycompItems lastObject] setIcon: [NSImage imageNamed:@"NSApplicationIcon"]];
537 [[mycompItems lastObject] setUntranslatedTitle: [NSString stringWithUTF8String: *ppsz_longname]];
538 [[mycompItems lastObject] setSdtype: SD_CAT_MYCOMPUTER];
542 msg_Warn( VLCIntf, "unknown SD type found, skipping (%s)", *ppsz_name );
547 free( *ppsz_longname );
549 [mycompItem setChildren: [NSArray arrayWithArray: mycompItems]];
550 [devicesItem setChildren: [NSArray arrayWithArray: devicesItems]];
551 [lanItem setChildren: [NSArray arrayWithArray: lanItems]];
552 [internetItem setChildren: [NSArray arrayWithArray: internetItems]];
553 [mycompItems release];
554 [devicesItems release];
556 [internetItems release];
558 free( ppsz_longnames );
559 free( p_categories );
561 [libraryItem setChildren: [NSArray arrayWithObjects: playlistItem, medialibraryItem, nil]];
562 [o_sidebaritems addObject: libraryItem];
563 if ([mycompItem hasChildren])
564 [o_sidebaritems addObject: mycompItem];
565 if ([devicesItem hasChildren])
566 [o_sidebaritems addObject: devicesItem];
567 if ([lanItem hasChildren])
568 [o_sidebaritems addObject: lanItem];
569 if ([internetItem hasChildren])
570 [o_sidebaritems addObject: internetItem];
572 [o_sidebar_view reloadData];
573 [o_sidebar_view selectRowIndexes:[NSIndexSet indexSetWithIndex:1] byExtendingSelection:NO];
574 [o_sidebar_view setDropItem:playlistItem dropChildIndex:NSOutlineViewDropOnItemIndex];
575 [o_sidebar_view registerForDraggedTypes:[NSArray arrayWithObjects: NSFilenamesPboardType, @"VLCPlaylistItemPboardType", nil]];
577 [o_sidebar_view setAutosaveName:@"mainwindow-sidebar"];
578 [(PXSourceList *)o_sidebar_view setDataSource:self];
579 [o_sidebar_view setDelegate:self];
580 [o_sidebar_view setAutosaveExpandedItems:YES];
582 [o_sidebar_view expandItem: libraryItem expandChildren: YES];
584 /* make sure we display the desired default appearance when VLC launches for the first time */
585 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
586 if (![defaults objectForKey:@"VLCFirstRun"])
588 [defaults setObject:[NSDate date] forKey:@"VLCFirstRun"];
590 NSUInteger i_sidebaritem_count = [o_sidebaritems count];
591 for (NSUInteger x = 0; x < i_sidebaritem_count; x++)
592 [o_sidebar_view expandItem: [o_sidebaritems objectAtIndex: x] expandChildren: YES];
595 if( b_dark_interface )
597 [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(windowResizedOrMoved:) name: NSWindowDidResizeNotification object: nil];
598 [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(windowResizedOrMoved:) name: NSWindowDidMoveNotification object: nil];
600 [self setBackgroundColor: [NSColor clearColor]];
601 [self setOpaque: NO];
603 [self setHasShadow:NO];
604 [self setHasShadow:YES];
606 NSRect winrect = [self frame];
607 CGFloat f_titleBarHeight = [o_titlebar_view frame].size.height;
609 [o_titlebar_view setFrame: NSMakeRect( 0, winrect.size.height - f_titleBarHeight,
610 winrect.size.width, f_titleBarHeight )];
611 [[self contentView] addSubview: o_titlebar_view positioned: NSWindowAbove relativeTo: o_split_view];
613 if (winrect.size.height > 100)
615 [self setFrame: winrect display:YES animate:YES];
616 previousSavedFrame = winrect;
619 winrect = [o_split_view frame];
620 winrect.size.height = winrect.size.height - f_titleBarHeight;
621 [o_split_view setFrame: winrect];
622 [o_video_view setFrame: winrect];
624 /* detached video window */
625 winrect = [o_detached_video_window frame];
628 [o_detached_titlebar_view setFrame: NSMakeRect( 0, winrect.size.height - f_titleBarHeight, winrect.size.width, f_titleBarHeight )];
629 [[o_detached_video_window contentView] addSubview: o_detached_titlebar_view positioned: NSWindowAbove relativeTo: nil];
632 o_color_backdrop = [[VLCColorView alloc] initWithFrame: [o_split_view frame]];
633 [[self contentView] addSubview: o_color_backdrop positioned: NSWindowBelow relativeTo: o_split_view];
634 [o_color_backdrop setAutoresizingMask:NSViewHeightSizable | NSViewWidthSizable];
639 frame = [o_time_sld_fancygradient_view frame];
640 frame.size.height = frame.size.height - 1;
641 frame.origin.y = frame.origin.y + 1;
642 [o_time_sld_fancygradient_view setFrame: frame];
644 frame = [o_detached_time_sld_fancygradient_view frame];
645 frame.size.height = frame.size.height - 1;
646 frame.origin.y = frame.origin.y + 1;
647 [o_detached_time_sld_fancygradient_view setFrame: frame];
649 [o_video_view setFrame: [o_split_view frame]];
650 [o_playlist_table setBorderType: NSNoBorder];
651 [o_sidebar_scrollview setBorderType: NSNoBorder];
655 frame = [o_time_sld_fancygradient_view frame];
656 frame.size.width = 0;
657 [o_time_sld_fancygradient_view setFrame: frame];
659 frame = [o_detached_time_sld_fancygradient_view frame];
660 frame.size.width = 0;
661 [o_detached_time_sld_fancygradient_view setFrame: frame];
665 [o_resize_view setImage: NULL];
666 [o_detached_resize_view setImage: NULL];
669 if ([self styleMask] & NSResizableWindowMask)
671 [o_resize_view removeFromSuperviewWithoutNeedingDisplay];
672 [o_detached_resize_view removeFromSuperviewWithoutNeedingDisplay];
675 [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(someWindowWillClose:) name: NSWindowWillCloseNotification object: nil];
676 [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(someWindowWillMiniaturize:) name: NSWindowWillMiniaturizeNotification object:nil];
677 [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(applicationWillTerminate:) name: NSApplicationWillTerminateNotification object: nil];
678 [[VLCMain sharedInstance] playbackModeUpdated];
680 [o_split_view setAutosaveName:@"10thanniversary-splitview"];
681 if (b_splitviewShouldBeHidden)
683 [self hideSplitView];
684 i_lastSplitViewHeight = 300;
687 /* sanity check for the window size */
688 frame = [self frame];
689 NSSize screenSize = [[self screen] frame].size;
690 if (screenSize.width <= frame.size.width || screenSize.height <= frame.size.height) {
691 nativeVideoSize = screenSize;
697 #pragma mark interface customization
698 - (void)toggleJumpButtons
700 b_show_jump_buttons = config_GetInt( VLCIntf, "macosx-show-playback-buttons" );
702 if (b_show_jump_buttons)
703 [self addJumpButtons:NO];
705 [self removeJumpButtons:NO];
708 - (void)addJumpButtons:(BOOL)b_fast
710 NSRect preliminaryFrame = [o_bwd_btn frame];
711 BOOL b_enabled = [o_bwd_btn isEnabled];
712 preliminaryFrame.size.width = 26.;
713 o_prev_btn = [[NSButton alloc] initWithFrame:preliminaryFrame];
714 [o_prev_btn setButtonType: NSMomentaryChangeButton];
715 [o_prev_btn setImage: [NSImage imageNamed:@"back-single"]];
716 [o_prev_btn setAlternateImage: [NSImage imageNamed:@"back-pressed-single"]];
717 [o_prev_btn setBezelStyle:NSRegularSquareBezelStyle];
718 [o_prev_btn setBordered:NO];
719 [o_prev_btn setTarget:self];
720 [o_prev_btn setAction:@selector(prev:)];
721 [o_prev_btn setToolTip: _NS("Previous")];
722 [[o_prev_btn cell] accessibilitySetOverrideValue:_NS("Previous") forAttribute:NSAccessibilityTitleAttribute];
723 [[o_prev_btn cell] accessibilitySetOverrideValue:_NS("Click to go to the previous playlist item.") forAttribute:NSAccessibilityDescriptionAttribute];
724 [o_prev_btn setEnabled: b_enabled];
726 o_next_btn = [[NSButton alloc] initWithFrame:preliminaryFrame];
727 [o_next_btn setButtonType: NSMomentaryChangeButton];
728 [o_next_btn setImage: [NSImage imageNamed:@"forward-single"]];
729 [o_next_btn setAlternateImage: [NSImage imageNamed:@"forward-pressed-single"]];
730 [o_next_btn setBezelStyle:NSRegularSquareBezelStyle];
731 [o_next_btn setBordered:NO];
732 [o_next_btn setTarget:self];
733 [o_next_btn setAction:@selector(next:)];
734 [o_next_btn setToolTip: _NS("Next")];
735 [[o_next_btn cell] accessibilitySetOverrideValue:_NS("Next") forAttribute:NSAccessibilityTitleAttribute];
736 [[o_next_btn cell] accessibilitySetOverrideValue:_NS("Click to go to the next playlist item.") forAttribute:NSAccessibilityDescriptionAttribute];
737 [o_next_btn setEnabled: b_enabled];
739 /* change the accessibility help for the backward/forward buttons accordingly */
740 [[o_bwd_btn cell] accessibilitySetOverrideValue:_NS("Click and hold to skip backward through the current media.") forAttribute:NSAccessibilityDescriptionAttribute];
741 [[o_fwd_btn cell] accessibilitySetOverrideValue:_NS("Click and hold to skip forward through the current media.") forAttribute:NSAccessibilityDescriptionAttribute];
745 #define moveItem( item ) \
746 frame = [item frame]; \
747 frame.origin.x = frame.origin.x + f_space; \
749 [item setFrame: frame]; \
751 [[item animator] setFrame: frame]
753 moveItem( o_bwd_btn );
754 moveItem( o_play_btn );
755 moveItem( o_fwd_btn );
757 moveItem( o_stop_btn );
758 moveItem( o_playlist_btn );
759 moveItem( o_repeat_btn );
760 moveItem( o_shuffle_btn );
763 #define resizeItem( item ) \
764 frame = [item frame]; \
765 frame.size.width = frame.size.width - f_space; \
766 frame.origin.x = frame.origin.x + f_space; \
768 [item setFrame: frame]; \
770 [[item animator] setFrame: frame]
772 resizeItem( o_time_sld );
773 resizeItem( o_progress_bar );
774 resizeItem( o_time_sld_background );
775 resizeItem( o_time_sld_fancygradient_view );
778 preliminaryFrame.origin.x = [o_next_btn frame].origin.x + 80. + [o_fwd_btn frame].size.width;
779 [o_next_btn setFrame: preliminaryFrame];
781 // wait until the animation is done, if displayed
783 [[self contentView] addSubview:o_prev_btn];
784 [[self contentView] addSubview:o_next_btn];
786 [[self contentView] performSelector:@selector(addSubview:) withObject:o_prev_btn afterDelay:.2];
787 [[self contentView] performSelector:@selector(addSubview:) withObject:o_next_btn afterDelay:.2];
790 [o_fwd_btn setAction:@selector(forward:)];
791 [o_bwd_btn setAction:@selector(backward:)];
794 - (void)removeJumpButtons:(BOOL)b_fast
796 if (!o_prev_btn || !o_next_btn )
800 [o_prev_btn setHidden: YES];
801 [o_next_btn setHidden: YES];
803 [[o_prev_btn animator] setHidden: YES];
804 [[o_next_btn animator] setHidden: YES];
806 [o_prev_btn removeFromSuperviewWithoutNeedingDisplay];
807 [o_next_btn removeFromSuperviewWithoutNeedingDisplay];
808 [o_prev_btn release];
809 [o_next_btn release];
811 /* change the accessibility help for the backward/forward buttons accordingly */
812 [[o_bwd_btn cell] accessibilitySetOverrideValue:_NS("Click to go to the previous playlist item. Hold to skip backward through the current media.") forAttribute:NSAccessibilityDescriptionAttribute];
813 [[o_fwd_btn cell] accessibilitySetOverrideValue:_NS("Click to go to the next playlist item. Hold to skip forward through the current media.") forAttribute:NSAccessibilityDescriptionAttribute];
817 #define moveItem( item ) \
818 frame = [item frame]; \
819 frame.origin.x = frame.origin.x - f_space; \
821 [item setFrame: frame]; \
823 [[item animator] setFrame: frame]
825 moveItem( o_bwd_btn );
826 moveItem( o_play_btn );
827 moveItem( o_fwd_btn );
829 moveItem( o_stop_btn );
830 moveItem( o_playlist_btn );
831 moveItem( o_repeat_btn );
832 moveItem( o_shuffle_btn );
835 #define resizeItem( item ) \
836 frame = [item frame]; \
837 frame.size.width = frame.size.width + f_space; \
838 frame.origin.x = frame.origin.x - f_space; \
840 [item setFrame: frame]; \
842 [[item animator] setFrame: frame]
844 resizeItem( o_time_sld );
845 resizeItem( o_progress_bar );
846 resizeItem( o_time_sld_background );
847 resizeItem( o_time_sld_fancygradient_view );
850 [o_bottombar_view setNeedsDisplay:YES];
852 [o_fwd_btn setAction:@selector(fwd:)];
853 [o_bwd_btn setAction:@selector(bwd:)];
856 - (void)togglePlaymodeButtons
858 b_show_playmode_buttons = config_GetInt( VLCIntf, "macosx-show-playmode-buttons" );
860 if (b_show_playmode_buttons)
861 [self addPlaymodeButtons:NO];
863 [self removePlaymodeButtons:NO];
866 - (void)addPlaymodeButtons:(BOOL)b_fast
869 float f_space = [o_repeat_btn frame].size.width + [o_shuffle_btn frame].size.width - 6.;
871 // FIXME: switch o_playlist_btn artwork
873 #define resizeItem( item ) \
874 frame = [item frame]; \
875 frame.size.width = frame.size.width - f_space; \
876 frame.origin.x = frame.origin.x + f_space; \
878 [item setFrame: frame]; \
880 [[item animator] setFrame: frame]
882 resizeItem( o_time_sld );
883 resizeItem( o_progress_bar );
884 resizeItem( o_time_sld_background );
885 resizeItem( o_time_sld_fancygradient_view );
889 [o_repeat_btn setHidden: NO];
890 [o_shuffle_btn setHidden: NO];
892 [[o_repeat_btn animator] setHidden: NO];
893 [[o_shuffle_btn animator] setHidden: NO];
897 - (void)removePlaymodeButtons:(BOOL)b_fast
900 float f_space = [o_repeat_btn frame].size.width + [o_shuffle_btn frame].size.width - 6.;
901 [o_repeat_btn setHidden: YES];
902 [o_shuffle_btn setHidden: YES];
904 // FIXME: switch o_playlist_btn artwork
906 #define resizeItem( item ) \
907 frame = [item frame]; \
908 frame.size.width = frame.size.width + f_space; \
909 frame.origin.x = frame.origin.x - f_space; \
911 [item setFrame: frame]; \
913 [[item animator] setFrame: frame]
915 resizeItem( o_time_sld );
916 resizeItem( o_progress_bar );
917 resizeItem( o_time_sld_background );
918 resizeItem( o_time_sld_fancygradient_view );
923 #pragma mark Button Actions
925 - (IBAction)play:(id)sender
927 [[VLCCoreInteraction sharedInstance] play];
930 - (void)resetPreviousButton
932 if (([NSDate timeIntervalSinceReferenceDate] - last_bwd_event) >= 0.35) {
933 // seems like no further event occurred, so let's switch the playback item
934 [[VLCCoreInteraction sharedInstance] previous];
935 just_triggered_previous = NO;
939 - (void)resetBackwardSkip
941 // the user stopped skipping, so let's allow him to change the item
942 if (([NSDate timeIntervalSinceReferenceDate] - last_bwd_event) >= 0.35)
943 just_triggered_previous = NO;
946 - (IBAction)prev:(id)sender
948 [[VLCCoreInteraction sharedInstance] previous];
951 - (IBAction)bwd:(id)sender
953 if(!just_triggered_previous)
955 just_triggered_previous = YES;
956 [self performSelector:@selector(resetPreviousButton)
962 if (([NSDate timeIntervalSinceReferenceDate] - last_fwd_event) > 0.16 )
964 // we just skipped 4 "continous" events, otherwise we are too fast
965 [[VLCCoreInteraction sharedInstance] backwardExtraShort];
966 last_bwd_event = [NSDate timeIntervalSinceReferenceDate];
967 [self performSelector:@selector(resetBackwardSkip)
974 - (IBAction)backward:(id)sender
976 [[VLCCoreInteraction sharedInstance] backwardShort];
979 - (void)resetNextButton
981 if (([NSDate timeIntervalSinceReferenceDate] - last_fwd_event) >= 0.35) {
982 // seems like no further event occurred, so let's switch the playback item
983 [[VLCCoreInteraction sharedInstance] next];
984 just_triggered_next = NO;
988 - (void)resetForwardSkip
990 // the user stopped skipping, so let's allow him to change the item
991 if (([NSDate timeIntervalSinceReferenceDate] - last_fwd_event) >= 0.35)
992 just_triggered_next = NO;
995 - (IBAction)next:(id)sender
997 [[VLCCoreInteraction sharedInstance] next];
1000 - (IBAction)forward:(id)sender
1002 [[VLCCoreInteraction sharedInstance] forwardShort];
1005 - (IBAction)fwd:(id)sender
1007 if(!just_triggered_next)
1009 just_triggered_next = YES;
1010 [self performSelector:@selector(resetNextButton)
1016 if (([NSDate timeIntervalSinceReferenceDate] - last_fwd_event) > 0.16 )
1018 // we just skipped 4 "continous" events, otherwise we are too fast
1019 [[VLCCoreInteraction sharedInstance] forwardExtraShort];
1020 last_fwd_event = [NSDate timeIntervalSinceReferenceDate];
1021 [self performSelector:@selector(resetForwardSkip)
1028 - (IBAction)stop:(id)sender
1030 [[VLCCoreInteraction sharedInstance] stop];
1033 - (void)resizePlaylistAfterCollapse
1036 plrect = [o_playlist_table frame];
1037 plrect.size.height = i_lastSplitViewHeight - 20.0; // actual pl top bar height, which differs from its frame
1038 [[o_playlist_table animator] setFrame: plrect];
1040 NSRect rightSplitRect;
1041 rightSplitRect = [o_right_split_view frame];
1042 plrect = [o_dropzone_box frame];
1043 plrect.origin.x = (rightSplitRect.size.width - plrect.size.width) / 2;
1044 plrect.origin.y = (rightSplitRect.size.height - plrect.size.height) / 2;
1045 [[o_dropzone_box animator] setFrame: plrect];
1048 - (void)makeSplitViewVisible
1050 if( b_dark_interface )
1051 [self setContentMinSize: NSMakeSize( 604., 288. + [o_titlebar_view frame].size.height )];
1053 [self setContentMinSize: NSMakeSize( 604., 288. )];
1055 NSRect old_frame = [self frame];
1056 float newHeight = [self minSize].height;
1057 if( old_frame.size.height < newHeight )
1059 NSRect new_frame = old_frame;
1060 new_frame.origin.y = old_frame.origin.y + old_frame.size.height - newHeight;
1061 new_frame.size.height = newHeight;
1063 [[self animator] setFrame: new_frame display: YES animate: YES];
1066 [o_video_view setHidden: YES];
1067 [o_split_view setHidden: NO];
1068 [self makeFirstResponder: nil];
1072 - (void)makeSplitViewHidden
1074 if( b_dark_interface )
1075 [self setContentMinSize: NSMakeSize( 604., f_min_video_height + [o_titlebar_view frame].size.height )];
1077 [self setContentMinSize: NSMakeSize( 604., f_min_video_height )];
1079 [o_split_view setHidden: YES];
1080 [o_video_view setHidden: NO];
1082 if( [[o_video_view subviews] count] > 0 )
1083 [self makeFirstResponder: [[o_video_view subviews] objectAtIndex:0]];
1086 - (IBAction)togglePlaylist:(id)sender
1088 if (![self isVisible] && sender != nil)
1090 [self makeKeyAndOrderFront: sender];
1094 BOOL b_activeVideo = [[VLCMain sharedInstance] activeVideoPlayback];
1095 BOOL b_restored = NO;
1097 // TODO: implement toggle playlist in this situation (triggerd via menu item).
1098 // but for now we block this case, to avoid displaying only the half
1099 if( b_nativeFullscreenMode && b_fullscreen && b_activeVideo && sender != nil )
1102 if (b_dropzone_active && ([[NSApp currentEvent] modifierFlags] & NSAlternateKeyMask) != 0)
1104 [self hideDropZone];
1108 if ( !(b_nativeFullscreenMode && b_fullscreen) && !b_splitview_removed && ( (([[NSApp currentEvent] modifierFlags] & NSAlternateKeyMask) != 0 && b_activeVideo)
1109 || (b_nonembedded && sender != nil)
1110 || (!b_activeVideo && sender != nil)
1111 || b_minimized_view ) )
1113 [self hideSplitView];
1117 if (b_splitview_removed)
1119 if( !b_nonembedded || ( sender != nil && b_nonembedded))
1120 [self showSplitView];
1123 b_minimized_view = YES;
1125 b_minimized_view = NO;
1133 if (([o_video_view isHidden] && b_activeVideo) || b_restored || (b_activeVideo && sender == nil) )
1134 [self makeSplitViewHidden];
1136 [self makeSplitViewVisible];
1140 [o_split_view setHidden: NO];
1141 [o_playlist_table setHidden: NO];
1142 [o_video_view setHidden: !b_activeVideo];
1143 if( b_activeVideo && [[o_video_view subviews] count] > 0 )
1144 [[o_video_view window] makeFirstResponder: [[o_video_view subviews] objectAtIndex:0]];
1149 - (void)setRepeatOne
1151 [o_repeat_btn setImage: o_repeat_one_img];
1152 [o_repeat_btn setAlternateImage: o_repeat_one_pressed_img];
1155 - (void)setRepeatAll
1157 [o_repeat_btn setImage: o_repeat_all_img];
1158 [o_repeat_btn setAlternateImage: o_repeat_all_pressed_img];
1161 - (void)setRepeatOff
1163 [o_repeat_btn setImage: o_repeat_img];
1164 [o_repeat_btn setAlternateImage: o_repeat_pressed_img];
1167 - (IBAction)repeat:(id)sender
1169 vlc_value_t looping,repeating;
1170 intf_thread_t * p_intf = VLCIntf;
1171 playlist_t * p_playlist = pl_Get( p_intf );
1173 var_Get( p_playlist, "repeat", &repeating );
1174 var_Get( p_playlist, "loop", &looping );
1176 if( !repeating.b_bool && !looping.b_bool )
1178 /* was: no repeating at all, switching to Repeat One */
1179 [[VLCCoreInteraction sharedInstance] repeatOne];
1180 [self setRepeatOne];
1182 else if( repeating.b_bool && !looping.b_bool )
1184 /* was: Repeat One, switching to Repeat All */
1185 [[VLCCoreInteraction sharedInstance] repeatAll];
1186 [self setRepeatAll];
1190 /* was: Repeat All or bug in VLC, switching to Repeat Off */
1191 [[VLCCoreInteraction sharedInstance] repeatOff];
1192 [self setRepeatOff];
1199 playlist_t *p_playlist = pl_Get( VLCIntf );
1200 b_value = var_GetBool( p_playlist, "random" );
1203 [o_shuffle_btn setImage: o_shuffle_on_img];
1204 [o_shuffle_btn setAlternateImage: o_shuffle_on_pressed_img];
1208 [o_shuffle_btn setImage: o_shuffle_img];
1209 [o_shuffle_btn setAlternateImage: o_shuffle_pressed_img];
1213 - (IBAction)shuffle:(id)sender
1215 [[VLCCoreInteraction sharedInstance] shuffle];
1219 - (IBAction)timeSliderAction:(id)sender
1222 input_thread_t * p_input;
1224 switch( [[NSApp currentEvent] type] )
1227 case NSLeftMouseDown:
1228 case NSLeftMouseDragged:
1229 f_updated = [sender floatValue];
1235 p_input = pl_CurrentInput( VLCIntf );
1236 if( p_input != NULL )
1241 pos.f_float = f_updated / 10000.;
1242 var_Set( p_input, "position", pos );
1243 [o_time_sld setFloatValue: f_updated];
1245 o_time = [[VLCStringUtility sharedInstance] getCurrentTimeAsString: p_input negative:[o_time_fld timeRemaining]];
1246 [o_time_fld setStringValue: o_time];
1247 [o_fspanel setStreamPos: f_updated andTime: o_time];
1248 vlc_object_release( p_input );
1252 - (IBAction)volumeAction:(id)sender
1254 if (sender == o_volume_sld)
1255 [[VLCCoreInteraction sharedInstance] setVolume: [sender intValue]];
1256 else if (sender == o_volume_down_btn)
1257 [[VLCCoreInteraction sharedInstance] toggleMute];
1259 [[VLCCoreInteraction sharedInstance] setVolume: AOUT_VOLUME_MAX];
1262 - (IBAction)effects:(id)sender
1264 [[VLCMainMenu sharedInstance] showAudioEffects: sender];
1267 - (IBAction)fullscreen:(id)sender
1269 [[VLCCoreInteraction sharedInstance] toggleFullscreen];
1272 - (IBAction)dropzoneButtonAction:(id)sender
1274 [[[VLCMain sharedInstance] open] openFileGeneric];
1278 #pragma mark overwritten default functionality
1279 - (BOOL)canBecomeKeyWindow
1284 - (BOOL)validateMenuItem:(NSMenuItem *)menuItem
1286 SEL s_menuAction = [menuItem action];
1288 if ((s_menuAction == @selector(performClose:)) || (s_menuAction == @selector(performMiniaturize:)) || (s_menuAction == @selector(performZoom:)))
1291 return [super validateMenuItem:menuItem];
1294 - (void)setTitle:(NSString *)title
1296 if (b_dark_interface)
1298 [o_titlebar_view setWindowTitle: title];
1300 [o_detached_titlebar_view setWindowTitle: title];
1302 if (b_nonembedded && [[VLCMain sharedInstance] activeVideoPlayback])
1303 [o_detached_video_window setTitle: title];
1304 [super setTitle: title];
1307 - (void)performClose:(id)sender
1309 NSWindow *o_key_window = [NSApp keyWindow];
1311 if (b_dark_interface || !b_video_deco)
1313 [o_key_window orderOut: sender];
1314 if ( [[VLCMain sharedInstance] activeVideoPlayback] && ( !b_nonembedded || o_key_window != self ))
1315 [[VLCCoreInteraction sharedInstance] stop];
1319 if( b_nonembedded && o_key_window != self )
1320 [o_detached_video_window performClose: sender];
1322 [super performClose: sender];
1326 - (void)performMiniaturize:(id)sender
1328 if (b_dark_interface)
1329 [self miniaturize: sender];
1331 [super performMiniaturize: sender];
1334 - (void)performZoom:(id)sender
1336 if (b_dark_interface)
1337 [self customZoom: sender];
1339 [super performZoom: sender];
1342 - (void)zoom:(id)sender
1344 if (b_dark_interface)
1345 [self customZoom: sender];
1347 [super zoom: sender];
1351 * Given a proposed frame rectangle, return a modified version
1352 * which will fit inside the screen.
1354 * This method is based upon NSWindow.m, part of the GNUstep GUI Library, licensed under LGPLv2+.
1355 * Authors: Scott Christley <scottc@net-community.com>, Venkat Ajjanagadde <venkat@ocbi.com>,
1356 * Felipe A. Rodriguez <far@ix.netcom.com>, Richard Frith-Macdonald <richard@brainstorm.co.uk>
1357 * Copyright (C) 1996 Free Software Foundation, Inc.
1359 - (NSRect) customConstrainFrameRect: (NSRect)frameRect toScreen: (NSScreen*)screen
1361 NSRect screenRect = [screen visibleFrame];
1364 /* Move top edge of the window inside the screen */
1365 difference = NSMaxY (frameRect) - NSMaxY (screenRect);
1368 frameRect.origin.y -= difference;
1371 /* If the window is resizable, resize it (if needed) so that the
1372 bottom edge is on the screen or can be on the screen when the user moves
1374 difference = NSMaxY (screenRect) - NSMaxY (frameRect);
1375 if (_styleMask & NSResizableWindowMask)
1379 difference2 = screenRect.origin.y - frameRect.origin.y;
1380 difference2 -= difference;
1381 // Take in account the space between the top of window and the top of the
1382 // screen which can be used to move the bottom of the window on the screen
1383 if (difference2 > 0)
1385 frameRect.size.height -= difference2;
1386 frameRect.origin.y += difference2;
1389 /* Ensure that resizing doesn't makewindow smaller than minimum */
1390 difference2 = [self minSize].height - frameRect.size.height;
1391 if (difference2 > 0)
1393 frameRect.size.height += difference2;
1394 frameRect.origin.y -= difference2;
1404 Zooms the receiver. This method calls the delegate method
1405 windowShouldZoom:toFrame: to determine if the window should
1406 be allowed to zoom to full screen.
1408 * This method is based upon NSWindow.m, part of the GNUstep GUI Library, licensed under LGPLv2+.
1409 * Authors: Scott Christley <scottc@net-community.com>, Venkat Ajjanagadde <venkat@ocbi.com>,
1410 * Felipe A. Rodriguez <far@ix.netcom.com>, Richard Frith-Macdonald <richard@brainstorm.co.uk>
1411 * Copyright (C) 1996 Free Software Foundation, Inc.
1413 - (void)customZoom:(id)sender
1415 NSRect maxRect = [[self screen] visibleFrame];
1416 NSRect currentFrame = [self frame];
1418 if ([[self delegate] respondsToSelector: @selector(windowWillUseStandardFrame:defaultFrame:)])
1420 maxRect = [[self delegate] windowWillUseStandardFrame: self defaultFrame: maxRect];
1423 maxRect = [self customConstrainFrameRect: maxRect toScreen: [self screen]];
1425 // Compare the new frame with the current one
1426 if ((abs(NSMaxX(maxRect) - NSMaxX(currentFrame)) < DIST)
1427 && (abs(NSMaxY(maxRect) - NSMaxY(currentFrame)) < DIST)
1428 && (abs(NSMinX(maxRect) - NSMinX(currentFrame)) < DIST)
1429 && (abs(NSMinY(maxRect) - NSMinY(currentFrame)) < DIST))
1431 // Already in zoomed mode, reset user frame, if stored
1432 if ([self frameAutosaveName] != nil)
1434 [self setFrame: previousSavedFrame display: YES animate: YES];
1435 [self saveFrameUsingName: [self frameAutosaveName]];
1440 if ([self frameAutosaveName] != nil)
1442 [self saveFrameUsingName: [self frameAutosaveName]];
1443 previousSavedFrame = [self frame];
1446 [self setFrame: maxRect display: YES animate: YES];
1449 - (void)windowResizedOrMoved:(NSNotification *)notification
1451 [self saveFrameUsingName: [self frameAutosaveName]];
1454 - (void)applicationWillTerminate:(NSNotification *)notification
1456 [self saveFrameUsingName: [self frameAutosaveName]];
1459 - (void)someWindowWillClose:(NSNotification *)notification
1461 if([notification object] == o_detached_video_window || ([notification object] == self && !b_nonembedded))
1463 if ([[VLCMain sharedInstance] activeVideoPlayback])
1464 [[VLCCoreInteraction sharedInstance] stop];
1468 - (void)someWindowWillMiniaturize:(NSNotification *)notification
1470 if (config_GetInt( VLCIntf, "macosx-pause-minimized" ))
1472 if([notification object] == o_detached_video_window || ([notification object] == self && !b_nonembedded))
1474 if([[VLCMain sharedInstance] activeVideoPlayback])
1475 [[VLCCoreInteraction sharedInstance] pause];
1480 - (NSSize)windowWillResize:(NSWindow *)window toSize:(NSSize)proposedFrameSize
1482 id videoWindow = [o_video_view window];
1483 if (![[VLCMain sharedInstance] activeVideoPlayback] || nativeVideoSize.width == 0. || nativeVideoSize.height == 0. || window != videoWindow)
1484 return proposedFrameSize;
1486 // needed when entering lion fullscreen mode
1488 return proposedFrameSize;
1490 if( [[VLCCoreInteraction sharedInstance] aspectRatioIsLocked] )
1492 NSRect videoWindowFrame = [videoWindow frame];
1493 NSRect viewRect = [o_video_view convertRect:[o_video_view bounds] toView: nil];
1494 NSRect contentRect = [videoWindow contentRectForFrameRect:videoWindowFrame];
1495 float marginy = viewRect.origin.y + videoWindowFrame.size.height - contentRect.size.height;
1496 float marginx = contentRect.size.width - viewRect.size.width;
1497 if( b_dark_interface && b_video_deco )
1498 marginy += [o_titlebar_view frame].size.height;
1500 proposedFrameSize.height = (proposedFrameSize.width - marginx) * nativeVideoSize.height / nativeVideoSize.width + marginy;
1503 return proposedFrameSize;
1507 #pragma mark Update interface and respond to foreign events
1508 - (void)showDropZone
1510 b_dropzone_active = YES;
1511 [o_right_split_view addSubview: o_dropzone_view positioned:NSWindowAbove relativeTo:o_playlist_table];
1512 [o_dropzone_view setFrame: [o_playlist_table frame]];
1513 [[o_playlist_table animator] setHidden:YES];
1516 - (void)hideDropZone
1518 b_dropzone_active = NO;
1519 [o_dropzone_view removeFromSuperview];
1520 [[o_playlist_table animator] setHidden: NO];
1523 - (void)hideSplitView
1525 NSRect winrect = [self frame];
1526 i_lastSplitViewHeight = [o_split_view frame].size.height;
1527 winrect.size.height = winrect.size.height - i_lastSplitViewHeight;
1528 winrect.origin.y = winrect.origin.y + i_lastSplitViewHeight;
1529 [self setFrame: winrect display: YES animate: YES];
1530 [self performSelector:@selector(hideDropZone) withObject:nil afterDelay:0.1];
1531 if (b_dark_interface)
1533 [self setContentMinSize: NSMakeSize( 604., [o_bottombar_view frame].size.height + [o_titlebar_view frame].size.height )];
1534 [self setContentMaxSize: NSMakeSize( FLT_MAX, [o_bottombar_view frame].size.height + [o_titlebar_view frame].size.height )];
1538 [self setContentMinSize: NSMakeSize( 604., [o_bottombar_view frame].size.height )];
1539 [self setContentMaxSize: NSMakeSize( FLT_MAX, [o_bottombar_view frame].size.height )];
1542 b_splitview_removed = YES;
1545 - (void)showSplitView
1547 [self updateWindow];
1548 if (b_dark_interface)
1549 [self setContentMinSize:NSMakeSize( 604., 288. + [o_titlebar_view frame].size.height )];
1551 [self setContentMinSize:NSMakeSize( 604., 288. )];
1552 [self setContentMaxSize: NSMakeSize( FLT_MAX, FLT_MAX )];
1555 winrect = [self frame];
1556 winrect.size.height = winrect.size.height + i_lastSplitViewHeight;
1557 winrect.origin.y = winrect.origin.y - i_lastSplitViewHeight;
1558 [self setFrame: winrect display: YES animate: YES];
1560 [self performSelector:@selector(resizePlaylistAfterCollapse) withObject: nil afterDelay:0.75];
1562 b_splitview_removed = NO;
1565 - (void)updateTimeSlider
1567 input_thread_t * p_input;
1568 p_input = pl_CurrentInput( VLCIntf );
1575 var_Get( p_input, "position", &pos );
1576 f_updated = 10000. * pos.f_float;
1577 [o_time_sld setFloatValue: f_updated];
1579 o_time = [[VLCStringUtility sharedInstance] getCurrentTimeAsString: p_input negative:[o_time_fld timeRemaining]];
1581 mtime_t dur = input_item_GetDuration( input_GetItem( p_input ) );
1583 [o_time_sld setEnabled: NO];
1584 [o_time_sld setHidden: YES];
1585 [o_time_sld_fancygradient_view setHidden: YES];
1587 [o_time_sld setEnabled: YES];
1588 [o_time_sld setHidden: NO];
1589 [o_time_sld_fancygradient_view setHidden: NO];
1592 [o_time_fld setStringValue: o_time];
1593 [o_time_fld setNeedsDisplay:YES];
1594 [o_fspanel setStreamPos: f_updated andTime: o_time];
1595 vlc_object_release( p_input );
1599 [o_time_sld setFloatValue: 0.0];
1600 [o_time_fld setStringValue: @"00:00"];
1601 [o_time_sld setEnabled: NO];
1602 [o_time_sld setHidden: YES];
1603 [o_time_sld_fancygradient_view setHidden: YES];
1605 [o_detached_time_sld_fancygradient_view setHidden: YES];
1610 [o_detached_time_sld setFloatValue: [o_time_sld floatValue]];
1611 [o_detached_time_sld setEnabled: [o_time_sld isEnabled]];
1612 [o_detached_time_fld setStringValue: [o_time_fld stringValue]];
1613 [o_detached_time_sld setHidden: [o_time_sld isHidden]];
1617 - (void)updateVolumeSlider
1619 int i_volume = [[VLCCoreInteraction sharedInstance] volume];
1620 BOOL b_muted = [[VLCCoreInteraction sharedInstance] mute];
1624 [o_volume_sld setIntValue: i_volume];
1625 [o_fspanel setVolumeLevel: i_volume];
1628 [o_volume_sld setIntValue: 0];
1630 [o_volume_sld setEnabled: !b_muted];
1631 [o_volume_up_btn setEnabled: !b_muted];
1636 NSAutoreleasePool *o_pool = [[NSAutoreleasePool alloc] init];
1637 input_thread_t * p_input;
1638 p_input = pl_CurrentInput( VLCIntf );
1642 char *format = var_InheritString( VLCIntf, "input-title-format" );
1643 char *formated = str_format_meta( pl_Get( VLCIntf ), format );
1645 aString = [NSString stringWithUTF8String:formated];
1648 char *uri = input_item_GetURI( input_GetItem( p_input ) );
1650 NSURL * o_url = [NSURL URLWithString: [NSString stringWithUTF8String: uri]];
1651 if ([o_url isFileURL])
1653 [self setRepresentedURL: o_url];
1654 [o_detached_video_window setRepresentedURL: o_url];
1656 [self setRepresentedURL: nil];
1657 [o_detached_video_window setRepresentedURL: nil];
1661 if ([aString isEqualToString:@""])
1663 if ([o_url isFileURL])
1664 aString = [[NSFileManager defaultManager] displayNameAtPath: [o_url path]];
1666 aString = [o_url absoluteString];
1669 [self setTitle: aString];
1670 [o_fspanel setStreamTitle: aString];
1671 vlc_object_release( p_input );
1675 [self setTitle: _NS("VLC media player")];
1676 [self setRepresentedURL: nil];
1682 - (void)updateWindow
1684 bool b_input = false;
1685 bool b_plmul = false;
1686 bool b_control = false;
1687 bool b_seekable = false;
1688 bool b_chapters = false;
1690 playlist_t * p_playlist = pl_Get( VLCIntf );
1693 b_plmul = playlist_CurrentSize( p_playlist ) > 1;
1696 input_thread_t * p_input = playlist_CurrentInput( p_playlist );
1698 bool b_buffering = NO;
1700 if( ( b_input = ( p_input != NULL ) ) )
1702 /* seekable streams */
1703 cachedInputState = input_GetState( p_input );
1704 if ( cachedInputState == INIT_S || cachedInputState == OPENING_S )
1707 /* seekable streams */
1708 b_seekable = var_GetBool( p_input, "can-seek" );
1710 /* check whether slow/fast motion is possible */
1711 b_control = var_GetBool( p_input, "can-rate" );
1713 /* chapters & titles */
1714 //FIXME! b_chapters = p_input->stream.i_area_nb > 1;
1716 vlc_object_release( p_input );
1721 [o_progress_bar startAnimation:self];
1722 [o_progress_bar setIndeterminate:YES];
1723 [o_progress_bar setHidden:NO];
1725 [o_progress_bar stopAnimation:self];
1726 [o_progress_bar setHidden:YES];
1729 [o_stop_btn setEnabled: b_input];
1730 [o_fwd_btn setEnabled: (b_seekable || b_plmul || b_chapters)];
1731 [o_bwd_btn setEnabled: (b_seekable || b_plmul || b_chapters)];
1732 if (b_show_jump_buttons)
1734 [o_prev_btn setEnabled: (b_seekable || b_plmul || b_chapters)];
1735 [o_next_btn setEnabled: (b_seekable || b_plmul || b_chapters)];
1739 [o_detached_fwd_btn setEnabled: (b_seekable || b_plmul || b_chapters)];
1740 [o_detached_bwd_btn setEnabled: (b_seekable || b_plmul || b_chapters)];
1742 [[VLCMainMenu sharedInstance] setRateControlsEnabled: b_control];
1744 [o_time_sld setEnabled: b_seekable];
1745 [self updateTimeSlider];
1746 [o_fspanel setSeekable: b_seekable];
1749 if ([[[VLCMain sharedInstance] playlist] currentPlaylistRoot] != p_playlist->p_local_category || p_playlist->p_local_category->i_children > 0)
1750 [self hideDropZone];
1752 [self showDropZone];
1754 [o_sidebar_view setNeedsDisplay:YES];
1759 [o_play_btn setImage: o_pause_img];
1760 [o_play_btn setAlternateImage: o_pause_pressed_img];
1761 [o_play_btn setToolTip: _NS("Pause")];
1764 [o_detached_play_btn setImage: o_pause_img];
1765 [o_detached_play_btn setAlternateImage: o_pause_pressed_img];
1766 [o_detached_play_btn setToolTip: _NS("Pause")];
1768 [o_fspanel setPause];
1773 [o_play_btn setImage: o_play_img];
1774 [o_play_btn setAlternateImage: o_play_pressed_img];
1775 [o_play_btn setToolTip: _NS("Play")];
1778 [o_detached_play_btn setImage: o_play_img];
1779 [o_detached_play_btn setAlternateImage: o_play_pressed_img];
1780 [o_detached_play_btn setToolTip: _NS("Play")];
1782 [o_fspanel setPlay];
1785 - (void)drawFancyGradientEffectForTimeSlider
1787 NSAutoreleasePool * o_pool = [[NSAutoreleasePool alloc] init];
1788 CGFloat f_value = [o_time_sld knobPosition];
1791 NSRect oldFrame = [o_time_sld_fancygradient_view frame];
1792 if (f_value != oldFrame.size.width)
1794 if ([o_time_sld_fancygradient_view isHidden])
1795 [o_time_sld_fancygradient_view setHidden: NO];
1796 [o_time_sld_fancygradient_view setFrame: NSMakeRect( oldFrame.origin.x, oldFrame.origin.y, f_value, oldFrame.size.height )];
1799 if (b_nonembedded && b_video_deco)
1801 f_value = [o_detached_time_sld knobPosition];
1802 oldFrame = [o_detached_time_sld_fancygradient_view frame];
1803 if (f_value != oldFrame.size.width)
1805 if ([o_detached_time_sld_fancygradient_view isHidden])
1806 [o_detached_time_sld_fancygradient_view setHidden: NO];
1807 [o_detached_time_sld_fancygradient_view setFrame: NSMakeRect( oldFrame.origin.x, oldFrame.origin.y, f_value, oldFrame.size.height )];
1814 frame = [o_time_sld_fancygradient_view frame];
1815 if (frame.size.width > 0)
1817 frame.size.width = 0;
1818 [o_time_sld_fancygradient_view setFrame: frame];
1822 frame = [o_detached_time_sld_fancygradient_view frame];
1823 frame.size.width = 0;
1824 [o_detached_time_sld_fancygradient_view setFrame: frame];
1827 [o_time_sld_fancygradient_view setHidden: YES];
1829 [o_detached_time_sld_fancygradient_view setHidden: YES];
1835 #pragma mark Video Output handling
1838 return o_video_view;
1841 - (void)setupVideoView
1843 // TODO: make lion fullscreen compatible with macosx-background and !embedded-video
1844 if( var_InheritBool( VLCIntf, "macosx-background" ) && !b_nativeFullscreenMode )
1846 msg_Dbg( VLCIntf, "Creating background window" );
1847 NSScreen *screen = [NSScreen screenWithDisplayID:(CGDirectDisplayID)var_InheritInteger( VLCIntf, "macosx-vdev" )];
1849 screen = [self screen];
1850 NSRect screen_rect = [screen frame];
1852 if( o_extra_video_window )
1853 [o_extra_video_window release];
1855 o_extra_video_window = [[VLCWindow alloc] initWithContentRect:screen_rect styleMask: NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO];
1856 [o_extra_video_window setLevel: CGWindowLevelForKey(kCGDesktopWindowLevelKey) + 1];
1857 [o_extra_video_window setBackgroundColor: [NSColor blackColor]];
1858 [o_extra_video_window setCanBecomeKeyWindow: NO];
1859 [o_extra_video_window setCanBecomeMainWindow: NO];
1860 [o_extra_video_window useOptimizedDrawing: YES];
1861 [o_extra_video_window setMovableByWindowBackground: NO];
1863 [o_video_view retain];
1864 if ([o_video_view superview] != NULL)
1865 [o_video_view removeFromSuperviewWithoutNeedingDisplay];
1866 screen_rect.origin.x = screen_rect.origin.y = 0;
1867 [o_video_view setFrame: screen_rect];
1868 [[o_extra_video_window contentView] addSubview: o_video_view positioned:NSWindowAbove relativeTo:nil];
1869 [o_video_view release];
1871 [o_extra_video_window orderBack:nil];
1873 b_nonembedded = YES;
1877 if ((var_InheritBool( VLCIntf, "embedded-video" ) || b_nativeFullscreenMode) && b_video_deco)
1879 if ([o_video_view window] != self)
1881 [o_video_view removeFromSuperviewWithoutNeedingDisplay];
1882 [o_video_view setFrame: [o_split_view frame]];
1883 [[self contentView] addSubview:o_video_view positioned:NSWindowAbove relativeTo:nil];
1889 if ([o_video_view superview] != NULL)
1890 [o_video_view removeFromSuperviewWithoutNeedingDisplay];
1893 videoFrame.size = [[o_detached_video_window contentView] frame].size;
1896 videoFrame.size.height -= [o_detached_bottombar_view frame].size.height;
1897 if( b_dark_interface )
1898 videoFrame.size.height -= [o_detached_titlebar_view frame].size.height;
1900 videoFrame.origin.x = .0;
1901 videoFrame.origin.y = [o_detached_bottombar_view frame].size.height;
1905 videoFrame.origin.y = .0;
1906 videoFrame.origin.x = .0;
1909 [o_video_view setFrame: videoFrame];
1910 [[o_detached_video_window contentView] addSubview: o_video_view positioned:NSWindowAbove relativeTo:nil];
1911 [o_detached_video_window setLevel:NSNormalWindowLevel];
1912 [o_detached_video_window useOptimizedDrawing: YES];
1913 b_nonembedded = YES;
1916 [[o_video_view window] makeKeyAndOrderFront: self];
1918 vout_thread_t *p_vout = getVout();
1921 if( var_GetBool( p_vout, "video-on-top" ) )
1922 [[o_video_view window] setLevel: NSStatusWindowLevel];
1924 [[o_video_view window] setLevel: NSNormalWindowLevel];
1925 vlc_object_release( p_vout );
1929 [[o_video_view window] setAlphaValue: config_GetFloat( VLCIntf, "macosx-opaqueness" )];
1932 - (void)setVideoplayEnabled
1934 BOOL b_videoPlayback = [[VLCMain sharedInstance] activeVideoPlayback];
1936 if( b_videoPlayback )
1938 // look for 'start at fullscreen'
1939 [[VLCMain sharedInstance] fullscreenChanged];
1943 [self makeFirstResponder: nil];
1944 [o_detached_video_window orderOut: nil];
1945 if( o_extra_video_window )
1946 [o_extra_video_window orderOut: nil];
1948 if( [self level] != NSNormalWindowLevel )
1949 [self setLevel: NSNormalWindowLevel];
1950 if( [o_detached_video_window level] != NSNormalWindowLevel )
1951 [o_detached_video_window setLevel: NSNormalWindowLevel];
1953 // restore alpha value to 1 for the case that macosx-opaqueness is set to < 1
1954 [self setAlphaValue:1.0];
1957 if( b_nativeFullscreenMode )
1959 if( [NSApp presentationOptions] & NSApplicationPresentationFullScreen )
1960 [o_bottombar_view setHidden: b_videoPlayback];
1962 [o_bottombar_view setHidden: NO];
1963 if( b_videoPlayback && b_fullscreen )
1964 [o_fspanel setActive: nil];
1965 if( !b_videoPlayback )
1966 [o_fspanel setNonActive: nil];
1969 if (!b_videoPlayback && b_fullscreen)
1971 if (!b_nativeFullscreenMode)
1972 [[VLCCoreInteraction sharedInstance] toggleFullscreen];
1976 - (void)resizeWindow
1978 if( b_fullscreen || ( b_nativeFullscreenMode && [NSApp presentationOptions] & NSApplicationPresentationFullScreen ) )
1981 id o_videoWindow = b_nonembedded ? o_detached_video_window : self;
1982 NSSize windowMinSize = [o_videoWindow minSize];
1983 NSRect screenFrame = [[o_videoWindow screen] visibleFrame];
1985 NSPoint topleftbase = NSMakePoint( 0, [o_videoWindow frame].size.height );
1986 NSPoint topleftscreen = [o_videoWindow convertBaseToScreen: topleftbase];
1988 unsigned int i_width = nativeVideoSize.width;
1989 unsigned int i_height = nativeVideoSize.height;
1990 if (i_width < windowMinSize.width)
1991 i_width = windowMinSize.width;
1992 if (i_height < f_min_video_height)
1993 i_height = f_min_video_height;
1995 /* Calculate the window's new size */
1997 new_frame.size.width = [o_videoWindow frame].size.width - [o_video_view frame].size.width + i_width;
1998 new_frame.size.height = [o_videoWindow frame].size.height - [o_video_view frame].size.height + i_height;
1999 new_frame.origin.x = topleftscreen.x;
2000 new_frame.origin.y = topleftscreen.y - new_frame.size.height;
2002 /* make sure the window doesn't exceed the screen size the window is on */
2003 if( new_frame.size.width > screenFrame.size.width )
2005 new_frame.size.width = screenFrame.size.width;
2006 new_frame.origin.x = screenFrame.origin.x;
2008 if( new_frame.size.height > screenFrame.size.height )
2010 new_frame.size.height = screenFrame.size.height;
2011 new_frame.origin.y = screenFrame.origin.y;
2013 if( new_frame.origin.y < screenFrame.origin.y )
2014 new_frame.origin.y = screenFrame.origin.y;
2016 CGFloat right_screen_point = screenFrame.origin.x + screenFrame.size.width;
2017 CGFloat right_window_point = new_frame.origin.x + new_frame.size.width;
2018 if( right_window_point > right_screen_point )
2019 new_frame.origin.x -= ( right_window_point - right_screen_point );
2021 [[o_videoWindow animator] setFrame:new_frame display:YES];
2024 - (void)setNativeVideoSize:(NSSize)size
2026 nativeVideoSize = size;
2028 if( var_InheritBool( VLCIntf, "macosx-video-autoresize" ) && !b_fullscreen && !var_InheritBool( VLCIntf, "macosx-background" ) )
2029 [self performSelectorOnMainThread:@selector(resizeWindow) withObject:nil waitUntilDone:NO];
2032 // Called automatically if window's acceptsMouseMovedEvents property is true
2033 - (void)mouseMoved:(NSEvent *)theEvent
2036 [self recreateHideMouseTimer];
2038 [super mouseMoved: theEvent];
2041 - (void)recreateHideMouseTimer
2043 if (t_hide_mouse_timer != nil) {
2044 [t_hide_mouse_timer invalidate];
2045 [t_hide_mouse_timer release];
2048 t_hide_mouse_timer = [NSTimer scheduledTimerWithTimeInterval:2
2050 selector:@selector(hideMouseCursor:)
2053 [t_hide_mouse_timer retain];
2056 // NSTimer selectors require this function signature as per Apple's docs
2057 - (void)hideMouseCursor:(NSTimer *)timer
2059 [NSCursor setHiddenUntilMouseMoves: YES];
2063 #pragma mark Fullscreen support
2064 - (void)showFullscreenController
2066 if (b_fullscreen && [[VLCMain sharedInstance] activeVideoPlayback] )
2072 return b_fullscreen;
2075 - (void)lockFullscreenAnimation
2077 [o_animation_lock lock];
2080 - (void)unlockFullscreenAnimation
2082 [o_animation_lock unlock];
2085 - (void)enterFullscreen
2087 NSMutableDictionary *dict1, *dict2;
2091 BOOL blackout_other_displays = var_InheritBool( VLCIntf, "macosx-black" );
2092 o_current_video_window = [o_video_view window];
2094 screen = [NSScreen screenWithDisplayID:(CGDirectDisplayID)var_InheritInteger( VLCIntf, "macosx-vdev" )];
2095 [self lockFullscreenAnimation];
2099 msg_Dbg( VLCIntf, "chosen screen isn't present, using current screen for fullscreen mode" );
2100 screen = [o_current_video_window screen];
2104 msg_Dbg( VLCIntf, "Using deepest screen" );
2105 screen = [NSScreen deepestScreen];
2108 screen_rect = [screen frame];
2110 [o_fullscreen_btn setState: YES];
2112 [o_detached_fullscreen_btn setState: YES];
2114 [self recreateHideMouseTimer];
2116 if( blackout_other_displays )
2117 [screen blackoutOtherScreens];
2119 /* Make sure we don't see the window flashes in float-on-top mode */
2120 i_originalLevel = [o_current_video_window level];
2121 [o_current_video_window setLevel:NSNormalWindowLevel];
2123 /* Only create the o_fullscreen_window if we are not in the middle of the zooming animation */
2124 if (!o_fullscreen_window)
2126 /* We can't change the styleMask of an already created NSWindow, so we create another window, and do eye catching stuff */
2128 rect = [[o_video_view superview] convertRect: [o_video_view frame] toView: nil]; /* Convert to Window base coord */
2129 rect.origin.x += [o_current_video_window frame].origin.x;
2130 rect.origin.y += [o_current_video_window frame].origin.y;
2131 o_fullscreen_window = [[VLCWindow alloc] initWithContentRect:rect styleMask: NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:YES];
2132 [o_fullscreen_window setBackgroundColor: [NSColor blackColor]];
2133 [o_fullscreen_window setCanBecomeKeyWindow: YES];
2134 [o_fullscreen_window setCanBecomeMainWindow: YES];
2136 if (![o_current_video_window isVisible] || [o_current_video_window alphaValue] == 0.0)
2138 /* We don't animate if we are not visible, instead we
2139 * simply fade the display */
2140 CGDisplayFadeReservationToken token;
2142 if( blackout_other_displays )
2144 CGAcquireDisplayFadeReservation( kCGMaxDisplayReservationInterval, &token );
2145 CGDisplayFade( token, 0.5, kCGDisplayBlendNormal, kCGDisplayBlendSolidColor, 0, 0, 0, YES );
2148 if ([screen mainScreen])
2149 [NSApp setPresentationOptions:(NSApplicationPresentationAutoHideDock | NSApplicationPresentationAutoHideMenuBar)];
2151 [[o_video_view superview] replaceSubview:o_video_view with:o_temp_view];
2152 [o_temp_view setFrame:[o_video_view frame]];
2153 [o_fullscreen_window setContentView:o_video_view];
2155 [o_fullscreen_window makeKeyAndOrderFront:self];
2156 [o_fullscreen_window orderFront:self animate:YES];
2158 [o_fullscreen_window setFrame:screen_rect display:YES animate:YES];
2159 [o_fullscreen_window setLevel:NSNormalWindowLevel];
2161 if( blackout_other_displays )
2163 CGDisplayFade( token, 0.3, kCGDisplayBlendSolidColor, kCGDisplayBlendNormal, 0, 0, 0, NO );
2164 CGReleaseDisplayFadeReservation( token );
2167 /* Will release the lock */
2168 [self hasBecomeFullscreen];
2173 /* Make sure we don't see the o_video_view disappearing of the screen during this operation */
2174 NSDisableScreenUpdates();
2175 [[o_video_view superview] replaceSubview:o_video_view with:o_temp_view];
2176 [o_temp_view setFrame:[o_video_view frame]];
2177 [o_fullscreen_window setContentView:o_video_view];
2178 [o_fullscreen_window makeKeyAndOrderFront:self];
2179 NSEnableScreenUpdates();
2182 /* We are in fullscreen (and no animation is running) */
2185 /* Make sure we are hidden */
2186 [o_current_video_window orderOut: self];
2188 [self unlockFullscreenAnimation];
2192 if (o_fullscreen_anim1)
2194 [o_fullscreen_anim1 stopAnimation];
2195 [o_fullscreen_anim1 release];
2197 if (o_fullscreen_anim2)
2199 [o_fullscreen_anim2 stopAnimation];
2200 [o_fullscreen_anim2 release];
2203 if ([screen mainScreen])
2204 [NSApp setPresentationOptions:(NSApplicationPresentationAutoHideDock | NSApplicationPresentationAutoHideMenuBar)];
2206 dict1 = [[NSMutableDictionary alloc] initWithCapacity:2];
2207 dict2 = [[NSMutableDictionary alloc] initWithCapacity:3];
2209 [dict1 setObject:o_current_video_window forKey:NSViewAnimationTargetKey];
2210 [dict1 setObject:NSViewAnimationFadeOutEffect forKey:NSViewAnimationEffectKey];
2212 [dict2 setObject:o_fullscreen_window forKey:NSViewAnimationTargetKey];
2213 [dict2 setObject:[NSValue valueWithRect:[o_fullscreen_window frame]] forKey:NSViewAnimationStartFrameKey];
2214 [dict2 setObject:[NSValue valueWithRect:screen_rect] forKey:NSViewAnimationEndFrameKey];
2216 /* Strategy with NSAnimation allocation:
2217 - Keep at most 2 animation at a time
2218 - leaveFullscreen/enterFullscreen are the only responsible for releasing and alloc-ing
2220 o_fullscreen_anim1 = [[NSViewAnimation alloc] initWithViewAnimations:[NSArray arrayWithObject:dict1]];
2221 o_fullscreen_anim2 = [[NSViewAnimation alloc] initWithViewAnimations:[NSArray arrayWithObject:dict2]];
2226 [o_fullscreen_anim1 setAnimationBlockingMode: NSAnimationNonblocking];
2227 [o_fullscreen_anim1 setDuration: 0.3];
2228 [o_fullscreen_anim1 setFrameRate: 30];
2229 [o_fullscreen_anim2 setAnimationBlockingMode: NSAnimationNonblocking];
2230 [o_fullscreen_anim2 setDuration: 0.2];
2231 [o_fullscreen_anim2 setFrameRate: 30];
2233 [o_fullscreen_anim2 setDelegate: self];
2234 [o_fullscreen_anim2 startWhenAnimation: o_fullscreen_anim1 reachesProgress: 1.0];
2236 [o_fullscreen_anim1 startAnimation];
2237 /* fullscreenAnimation will be unlocked when animation ends */
2240 - (void)hasBecomeFullscreen
2242 if( [[o_video_view subviews] count] > 0 )
2243 [o_fullscreen_window makeFirstResponder: [[o_video_view subviews] objectAtIndex:0]];
2245 [o_fullscreen_window makeKeyWindow];
2246 [o_fullscreen_window setAcceptsMouseMovedEvents: YES];
2248 /* tell the fspanel to move itself to front next time it's triggered */
2249 [o_fspanel setVoutWasUpdated: (int)[[o_fullscreen_window screen] displayID]];
2250 [o_fspanel setActive: nil];
2252 if( [o_current_video_window isVisible] )
2253 [o_current_video_window orderOut: self];
2256 [self unlockFullscreenAnimation];
2259 - (void)leaveFullscreen
2261 [self leaveFullscreenAndFadeOut: NO];
2264 - (void)leaveFullscreenAndFadeOut: (BOOL)fadeout
2266 NSMutableDictionary *dict1, *dict2;
2268 BOOL blackout_other_displays = var_InheritBool( VLCIntf, "macosx-black" );
2270 if( !o_current_video_window )
2273 [self lockFullscreenAnimation];
2275 [o_fullscreen_btn setState: NO];
2277 [o_detached_fullscreen_btn setState: NO];
2279 /* We always try to do so */
2280 [NSScreen unblackoutScreens];
2282 vout_thread_t *p_vout = getVout();
2285 if( var_GetBool( p_vout, "video-on-top" ) )
2286 [[o_video_view window] setLevel: NSStatusWindowLevel];
2288 [[o_video_view window] setLevel: NSNormalWindowLevel];
2289 vlc_object_release( p_vout );
2291 [[o_video_view window] makeKeyAndOrderFront: nil];
2293 /* Don't do anything if o_fullscreen_window is already closed */
2294 if (!o_fullscreen_window)
2296 [self unlockFullscreenAnimation];
2302 /* We don't animate if we are not visible, instead we
2303 * simply fade the display */
2304 CGDisplayFadeReservationToken token;
2306 if( blackout_other_displays )
2308 CGAcquireDisplayFadeReservation( kCGMaxDisplayReservationInterval, &token );
2309 CGDisplayFade( token, 0.3, kCGDisplayBlendNormal, kCGDisplayBlendSolidColor, 0, 0, 0, YES );
2312 [o_fspanel setNonActive: nil];
2313 [NSApp setPresentationOptions: NSApplicationPresentationDefault];
2315 /* Will release the lock */
2316 [self hasEndedFullscreen];
2318 /* Our window is hidden, and might be faded. We need to workaround that, so note it
2320 b_window_is_invisible = YES;
2322 if( blackout_other_displays )
2324 CGDisplayFade( token, 0.5, kCGDisplayBlendSolidColor, kCGDisplayBlendNormal, 0, 0, 0, NO );
2325 CGReleaseDisplayFadeReservation( token );
2331 [o_current_video_window setAlphaValue: 0.0];
2332 [o_current_video_window orderFront: self];
2333 [[o_video_view window] orderFront: self];
2335 [o_fspanel setNonActive: nil];
2336 [NSApp setPresentationOptions:(NSApplicationPresentationDefault)];
2338 if (o_fullscreen_anim1)
2340 [o_fullscreen_anim1 stopAnimation];
2341 [o_fullscreen_anim1 release];
2343 if (o_fullscreen_anim2)
2345 [o_fullscreen_anim2 stopAnimation];
2346 [o_fullscreen_anim2 release];
2349 frame = [[o_temp_view superview] convertRect: [o_temp_view frame] toView: nil]; /* Convert to Window base coord */
2350 frame.origin.x += [o_current_video_window frame].origin.x;
2351 frame.origin.y += [o_current_video_window frame].origin.y;
2353 dict2 = [[NSMutableDictionary alloc] initWithCapacity:2];
2354 [dict2 setObject:o_current_video_window forKey:NSViewAnimationTargetKey];
2355 [dict2 setObject:NSViewAnimationFadeInEffect forKey:NSViewAnimationEffectKey];
2357 o_fullscreen_anim2 = [[NSViewAnimation alloc] initWithViewAnimations:[NSArray arrayWithObjects:dict2, nil]];
2360 [o_fullscreen_anim2 setAnimationBlockingMode: NSAnimationNonblocking];
2361 [o_fullscreen_anim2 setDuration: 0.3];
2362 [o_fullscreen_anim2 setFrameRate: 30];
2364 [o_fullscreen_anim2 setDelegate: self];
2366 dict1 = [[NSMutableDictionary alloc] initWithCapacity:3];
2368 [dict1 setObject:o_fullscreen_window forKey:NSViewAnimationTargetKey];
2369 [dict1 setObject:[NSValue valueWithRect:[o_fullscreen_window frame]] forKey:NSViewAnimationStartFrameKey];
2370 [dict1 setObject:[NSValue valueWithRect:frame] forKey:NSViewAnimationEndFrameKey];
2372 o_fullscreen_anim1 = [[NSViewAnimation alloc] initWithViewAnimations:[NSArray arrayWithObjects:dict1, nil]];
2375 [o_fullscreen_anim1 setAnimationBlockingMode: NSAnimationNonblocking];
2376 [o_fullscreen_anim1 setDuration: 0.2];
2377 [o_fullscreen_anim1 setFrameRate: 30];
2378 [o_fullscreen_anim2 startWhenAnimation: o_fullscreen_anim1 reachesProgress: 1.0];
2380 /* Make sure o_fullscreen_window is the frontmost window */
2381 [o_fullscreen_window orderFront: self];
2383 [o_fullscreen_anim1 startAnimation];
2384 /* fullscreenAnimation will be unlocked when animation ends */
2387 - (void)hasEndedFullscreen
2391 /* This function is private and should be only triggered at the end of the fullscreen change animation */
2392 /* Make sure we don't see the o_video_view disappearing of the screen during this operation */
2393 NSDisableScreenUpdates();
2394 [o_video_view retain];
2395 [o_video_view removeFromSuperviewWithoutNeedingDisplay];
2396 [[o_temp_view superview] replaceSubview:o_temp_view with:o_video_view];
2397 [o_video_view release];
2398 [o_video_view setFrame:[o_temp_view frame]];
2399 if( [[o_video_view subviews] count] > 0 )
2400 [[o_video_view window] makeFirstResponder: [[o_video_view subviews] objectAtIndex:0]];
2401 if( !b_nonembedded )
2402 [super makeKeyAndOrderFront:self]; /* our version contains a workaround */
2404 [[o_video_view window] makeKeyAndOrderFront: self];
2405 [o_fullscreen_window orderOut: self];
2406 NSEnableScreenUpdates();
2408 [o_fullscreen_window release];
2409 o_fullscreen_window = nil;
2410 [[o_video_view window] setLevel:i_originalLevel];
2411 [[o_video_view window] setAlphaValue: config_GetFloat( VLCIntf, "macosx-opaqueness" )];
2413 // if we quit fullscreen because there is no video anymore, make sure non-embedded window is not visible
2414 if( ![[VLCMain sharedInstance] activeVideoPlayback] && b_nonembedded )
2415 [o_current_video_window orderOut: self];
2417 o_current_video_window = nil;
2418 [self unlockFullscreenAnimation];
2421 - (void)animationDidEnd:(NSAnimation*)animation
2423 NSArray *viewAnimations;
2424 if( o_makekey_anim == animation )
2426 [o_makekey_anim release];
2429 if ([animation currentValue] < 1.0)
2432 /* Fullscreen ended or started (we are a delegate only for leaveFullscreen's/enterFullscren's anim2) */
2433 viewAnimations = [o_fullscreen_anim2 viewAnimations];
2434 if ([viewAnimations count] >=1 &&
2435 [[[viewAnimations objectAtIndex: 0] objectForKey: NSViewAnimationEffectKey] isEqualToString:NSViewAnimationFadeInEffect])
2437 /* Fullscreen ended */
2438 [self hasEndedFullscreen];
2442 /* Fullscreen started */
2443 [self hasBecomeFullscreen];
2447 - (void)makeKeyAndOrderFront: (id)sender
2450 * when we exit fullscreen and fade out, we may endup in
2451 * having a window that is faded. We can't have it fade in unless we
2454 if(!b_window_is_invisible)
2456 /* Make sure we don't do it too much */
2457 [super makeKeyAndOrderFront: sender];
2461 [super setAlphaValue:0.0f];
2462 [super makeKeyAndOrderFront: sender];
2464 NSMutableDictionary * dict = [[NSMutableDictionary alloc] initWithCapacity:2];
2465 [dict setObject:self forKey:NSViewAnimationTargetKey];
2466 [dict setObject:NSViewAnimationFadeInEffect forKey:NSViewAnimationEffectKey];
2468 o_makekey_anim = [[NSViewAnimation alloc] initWithViewAnimations:[NSArray arrayWithObject:dict]];
2471 [o_makekey_anim setAnimationBlockingMode: NSAnimationNonblocking];
2472 [o_makekey_anim setDuration: 0.1];
2473 [o_makekey_anim setFrameRate: 30];
2474 [o_makekey_anim setDelegate: self];
2476 [o_makekey_anim startAnimation];
2477 b_window_is_invisible = NO;
2479 /* fullscreenAnimation will be unlocked when animation ends */
2483 #pragma mark Lion native fullscreen handling
2484 - (void)windowWillEnterFullScreen:(NSNotification *)notification
2486 // workaround, see #6668
2487 [NSApp setPresentationOptions:(NSApplicationPresentationFullScreen | NSApplicationPresentationAutoHideDock | NSApplicationPresentationAutoHideMenuBar)];
2489 var_SetBool( pl_Get( VLCIntf ), "fullscreen", true );
2491 vout_thread_t *p_vout = getVout();
2494 var_SetBool( p_vout, "fullscreen", true );
2495 vlc_object_release( p_vout );
2498 [o_video_view setFrame: [[self contentView] frame]];
2501 [self recreateHideMouseTimer];
2502 i_originalLevel = [self level];
2503 [self setLevel:NSNormalWindowLevel];
2505 if (b_dark_interface)
2507 [o_titlebar_view removeFromSuperviewWithoutNeedingDisplay];
2510 CGFloat f_titleBarHeight = [o_titlebar_view frame].size.height;
2511 winrect = [self frame];
2513 winrect.size.height = winrect.size.height - f_titleBarHeight;
2514 [self setFrame: winrect display:NO animate:NO];
2515 winrect = [o_split_view frame];
2516 winrect.size.height = winrect.size.height + f_titleBarHeight;
2517 [o_split_view setFrame: winrect];
2520 if ([[VLCMain sharedInstance] activeVideoPlayback])
2521 [o_bottombar_view setHidden: YES];
2523 [self setMovableByWindowBackground: NO];
2526 - (void)windowDidEnterFullScreen:(NSNotification *)notification
2528 // Indeed, we somehow can have an "inactive" fullscreen (but a visible window!).
2529 // But this creates some problems when leaving fs over remote intfs, so activate app here.
2530 [NSApp activateIgnoringOtherApps:YES];
2532 [o_fspanel setVoutWasUpdated: (int)[[self screen] displayID]];
2533 [o_fspanel setActive: nil];
2536 - (void)windowWillExitFullScreen:(NSNotification *)notification
2539 var_SetBool( pl_Get( VLCIntf ), "fullscreen", false );
2541 vout_thread_t *p_vout = getVout();
2544 var_SetBool( p_vout, "fullscreen", false );
2545 vlc_object_release( p_vout );
2548 [o_video_view setFrame: [o_split_view frame]];
2549 [NSCursor setHiddenUntilMouseMoves: NO];
2550 [o_fspanel setNonActive: nil];
2551 [self setLevel:i_originalLevel];
2554 if (b_dark_interface)
2557 CGFloat f_titleBarHeight = [o_titlebar_view frame].size.height;
2558 winrect = [self frame];
2560 [o_titlebar_view setFrame: NSMakeRect( 0, winrect.size.height - f_titleBarHeight,
2561 winrect.size.width, f_titleBarHeight )];
2562 [[self contentView] addSubview: o_titlebar_view];
2564 winrect.size.height = winrect.size.height + f_titleBarHeight;
2565 [self setFrame: winrect display:NO animate:NO];
2566 winrect = [o_split_view frame];
2567 winrect.size.height = winrect.size.height - f_titleBarHeight;
2568 [o_split_view setFrame: winrect];
2569 [o_video_view setFrame: winrect];
2572 if ([[VLCMain sharedInstance] activeVideoPlayback])
2573 [o_bottombar_view setHidden: NO];
2575 [self setMovableByWindowBackground: YES];
2579 #pragma mark split view delegate
2580 - (CGFloat)splitView:(NSSplitView *)splitView constrainMaxCoordinate:(CGFloat)proposedMax ofSubviewAt:(NSInteger)dividerIndex
2582 if (dividerIndex == 0)
2588 - (CGFloat)splitView:(NSSplitView *)splitView constrainMinCoordinate:(CGFloat)proposedMin ofSubviewAt:(NSInteger)dividerIndex
2590 if (dividerIndex == 0)
2596 - (BOOL)splitView:(NSSplitView *)splitView canCollapseSubview:(NSView *)subview
2598 return ([subview isEqual:o_left_split_view]);
2601 - (BOOL)splitView:(NSSplitView *)splitView shouldAdjustSizeOfSubview:(NSView *)subview
2603 if ([subview isEqual:o_left_split_view])
2609 #pragma mark Side Bar Data handling
2610 /* taken under BSD-new from the PXSourceList sample project, adapted for VLC */
2611 - (NSUInteger)sourceList:(PXSourceList*)sourceList numberOfChildrenOfItem:(id)item
2613 //Works the same way as the NSOutlineView data source: `nil` means a parent item
2615 return [o_sidebaritems count];
2617 return [[item children] count];
2621 - (id)sourceList:(PXSourceList*)aSourceList child:(NSUInteger)index ofItem:(id)item
2623 //Works the same way as the NSOutlineView data source: `nil` means a parent item
2625 return [o_sidebaritems objectAtIndex:index];
2627 return [[item children] objectAtIndex:index];
2631 - (id)sourceList:(PXSourceList*)aSourceList objectValueForItem:(id)item
2633 return [item title];
2636 - (void)sourceList:(PXSourceList*)aSourceList setObjectValue:(id)object forItem:(id)item
2638 [item setTitle:object];
2641 - (BOOL)sourceList:(PXSourceList*)aSourceList isItemExpandable:(id)item
2643 return [item hasChildren];
2647 - (BOOL)sourceList:(PXSourceList*)aSourceList itemHasBadge:(id)item
2649 if ([[item identifier] isEqualToString: @"playlist"] || [[item identifier] isEqualToString: @"medialibrary"])
2652 return [item hasBadge];
2656 - (NSInteger)sourceList:(PXSourceList*)aSourceList badgeValueForItem:(id)item
2658 playlist_t * p_playlist = pl_Get( VLCIntf );
2659 NSInteger i_playlist_size;
2661 if ([[item identifier] isEqualToString: @"playlist"])
2664 i_playlist_size = p_playlist->p_local_category->i_children;
2667 return i_playlist_size;
2669 if ([[item identifier] isEqualToString: @"medialibrary"])
2672 i_playlist_size = p_playlist->p_ml_category->i_children;
2675 return i_playlist_size;
2678 return [item badgeValue];
2682 - (BOOL)sourceList:(PXSourceList*)aSourceList itemHasIcon:(id)item
2684 return [item hasIcon];
2688 - (NSImage*)sourceList:(PXSourceList*)aSourceList iconForItem:(id)item
2693 - (NSMenu*)sourceList:(PXSourceList*)aSourceList menuForEvent:(NSEvent*)theEvent item:(id)item
2695 if ([theEvent type] == NSRightMouseDown || ([theEvent type] == NSLeftMouseDown && ([theEvent modifierFlags] & NSControlKeyMask) == NSControlKeyMask))
2700 if ([item sdtype] > 0)
2702 m = [[NSMenu alloc] init];
2703 playlist_t * p_playlist = pl_Get( VLCIntf );
2704 BOOL sd_loaded = playlist_IsServicesDiscoveryLoaded( p_playlist, [[item identifier] UTF8String] );
2706 [m addItemWithTitle:_NS("Enable") action:@selector(sdmenuhandler:) keyEquivalent:@""];
2708 [m addItemWithTitle:_NS("Disable") action:@selector(sdmenuhandler:) keyEquivalent:@""];
2709 [[m itemAtIndex:0] setRepresentedObject: [item identifier]];
2711 return [m autorelease];
2718 - (IBAction)sdmenuhandler:(id)sender
2720 NSString * identifier = [sender representedObject];
2721 if ([identifier length] > 0 && ![identifier isEqualToString:@"lua{sd='freebox',longname='Freebox TV'}"])
2723 playlist_t * p_playlist = pl_Get( VLCIntf );
2724 BOOL sd_loaded = playlist_IsServicesDiscoveryLoaded( p_playlist, [identifier UTF8String] );
2727 playlist_ServicesDiscoveryAdd( p_playlist, [identifier UTF8String] );
2729 playlist_ServicesDiscoveryRemove( p_playlist, [identifier UTF8String] );
2734 #pragma mark Side Bar Delegate Methods
2735 /* taken under BSD-new from the PXSourceList sample project, adapted for VLC */
2736 - (BOOL)sourceList:(PXSourceList*)aSourceList isGroupAlwaysExpanded:(id)group
2738 if ([[group identifier] isEqualToString:@"library"])
2744 - (void)sourceListSelectionDidChange:(NSNotification *)notification
2746 playlist_t * p_playlist = pl_Get( VLCIntf );
2748 NSIndexSet *selectedIndexes = [o_sidebar_view selectedRowIndexes];
2749 id item = [o_sidebar_view itemAtRow:[selectedIndexes firstIndex]];
2752 //Set the label text to represent the new selection
2753 if ([item sdtype] > -1 && [[item identifier] length] > 0)
2755 BOOL sd_loaded = playlist_IsServicesDiscoveryLoaded( p_playlist, [[item identifier] UTF8String] );
2758 playlist_ServicesDiscoveryAdd( p_playlist, [[item identifier] UTF8String] );
2762 [o_chosen_category_lbl setStringValue:[item title]];
2764 if ([[item identifier] isEqualToString:@"playlist"])
2766 [[[VLCMain sharedInstance] playlist] setPlaylistRoot:p_playlist->p_local_category];
2768 else if([[item identifier] isEqualToString:@"medialibrary"])
2770 [[[VLCMain sharedInstance] playlist] setPlaylistRoot:p_playlist->p_ml_category];
2774 playlist_item_t * pl_item;
2776 pl_item = playlist_ChildSearchName( p_playlist->p_root, [[item untranslatedTitle] UTF8String] );
2778 [[[VLCMain sharedInstance] playlist] setPlaylistRoot: pl_item];
2782 if ([[[VLCMain sharedInstance] playlist] currentPlaylistRoot] != p_playlist->p_local_category || p_playlist->p_local_category->i_children > 0)
2783 [self hideDropZone];
2785 [self showDropZone];
2789 - (NSDragOperation)sourceList:(PXSourceList *)aSourceList validateDrop:(id <NSDraggingInfo>)info proposedItem:(id)item proposedChildIndex:(NSInteger)index
2791 if ([[item identifier] isEqualToString:@"playlist"] || [[item identifier] isEqualToString:@"medialibrary"] )
2793 NSPasteboard *o_pasteboard = [info draggingPasteboard];
2794 if ([[o_pasteboard types] containsObject: @"VLCPlaylistItemPboardType"] || [[o_pasteboard types] containsObject: NSFilenamesPboardType])
2795 return NSDragOperationGeneric;
2797 return NSDragOperationNone;
2800 - (BOOL)sourceList:(PXSourceList *)aSourceList acceptDrop:(id <NSDraggingInfo>)info item:(id)item childIndex:(NSInteger)index
2802 NSPasteboard *o_pasteboard = [info draggingPasteboard];
2804 playlist_t * p_playlist = pl_Get( VLCIntf );
2805 playlist_item_t *p_node;
2807 if ([[item identifier] isEqualToString:@"playlist"])
2808 p_node = p_playlist->p_local_category;
2810 p_node = p_playlist->p_ml_category;
2812 if( [[o_pasteboard types] containsObject: NSFilenamesPboardType] )
2814 NSArray *o_values = [[o_pasteboard propertyListForType: NSFilenamesPboardType] sortedArrayUsingSelector: @selector(caseInsensitiveCompare:)];
2815 NSUInteger count = [o_values count];
2816 NSMutableArray *o_array = [NSMutableArray arrayWithCapacity:count];
2818 for( NSUInteger i = 0; i < count; i++)
2820 NSDictionary *o_dic;
2821 char *psz_uri = vlc_path2uri([[o_values objectAtIndex:i] UTF8String], NULL);
2825 o_dic = [NSDictionary dictionaryWithObject:[NSString stringWithCString:psz_uri encoding:NSUTF8StringEncoding] forKey:@"ITEM_URL"];
2829 [o_array addObject: o_dic];
2832 [[[VLCMain sharedInstance] playlist] appendNodeArray:o_array inNode: p_node atPos:-1 enqueue:YES];
2835 else if( [[o_pasteboard types] containsObject: @"VLCPlaylistItemPboardType"] )
2837 NSArray * array = [[[VLCMain sharedInstance] playlist] draggedItems];
2839 NSUInteger count = [array count];
2840 playlist_item_t * p_item = NULL;
2843 for( NSUInteger i = 0; i < count; i++ )
2845 p_item = [[array objectAtIndex:i] pointerValue];
2846 if( !p_item ) continue;
2847 playlist_NodeAddCopy( p_playlist, p_item, p_node, PLAYLIST_END );
2856 - (id)sourceList:(PXSourceList *)aSourceList persistentObjectForItem:(id)item
2858 return [item identifier];
2861 - (id)sourceList:(PXSourceList *)aSourceList itemForPersistentObject:(id)object
2863 /* the following code assumes for sakes of simplicity that only the top level
2864 * items are allowed to have children */
2866 NSArray * array = [NSArray arrayWithArray: o_sidebaritems]; // read-only arrays are noticebly faster
2867 NSUInteger count = [array count];
2871 for (NSUInteger x = 0; x < count; x++)
2873 id item = [array objectAtIndex: x]; // save one objc selector call
2874 if ([[item identifier] isEqualToString:object])
2882 #pragma mark Accessibility stuff
2884 - (NSArray *)accessibilityAttributeNames
2886 if( !b_dark_interface )
2887 return [super accessibilityAttributeNames];
2889 static NSMutableArray *attributes = nil;
2890 if ( attributes == nil ) {
2891 attributes = [[super accessibilityAttributeNames] mutableCopy];
2892 NSArray *appendAttributes = [NSArray arrayWithObjects: NSAccessibilitySubroleAttribute,
2893 NSAccessibilityCloseButtonAttribute,
2894 NSAccessibilityMinimizeButtonAttribute,
2895 NSAccessibilityZoomButtonAttribute,
2898 for( NSString *attribute in appendAttributes )
2900 if( ![attributes containsObject:attribute] )
2901 [attributes addObject:attribute];
2907 - (id)accessibilityAttributeValue: (NSString*)o_attribute_name
2909 if( b_dark_interface )
2911 VLCMainWindowTitleView *o_tbv = o_titlebar_view;
2913 if( [o_attribute_name isEqualTo: NSAccessibilitySubroleAttribute] )
2914 return NSAccessibilityStandardWindowSubrole;
2916 if( [o_attribute_name isEqualTo: NSAccessibilityCloseButtonAttribute] )
2917 return [[o_tbv closeButton] cell];
2919 if( [o_attribute_name isEqualTo: NSAccessibilityMinimizeButtonAttribute] )
2920 return [[o_tbv minimizeButton] cell];
2922 if( [o_attribute_name isEqualTo: NSAccessibilityZoomButtonAttribute] )
2923 return [[o_tbv zoomButton] cell];
2926 return [super accessibilityAttributeValue: o_attribute_name];
2929 - (id)detachedTitlebarView
2931 return o_detached_titlebar_view;
2935 @implementation VLCDetachedVideoWindow
2937 - (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)styleMask
2938 backing:(NSBackingStoreType)backingType defer:(BOOL)flag
2940 b_dark_interface = config_GetInt( VLCIntf, "macosx-interfacestyle" );
2941 b_video_deco = var_InheritBool( VLCIntf, "video-deco" );
2943 if (b_dark_interface || !b_video_deco)
2945 #ifdef MAC_OS_X_VERSION_10_7
2947 styleMask = NSBorderlessWindowMask | NSResizableWindowMask;
2949 styleMask = NSBorderlessWindowMask;
2951 styleMask = NSBorderlessWindowMask;
2955 self = [super initWithContentRect:contentRect styleMask:styleMask
2956 backing:backingType defer:flag];
2958 /* we want to be moveable regardless of our style */
2959 [self setMovableByWindowBackground: YES];
2961 /* we don't want this window to be restored on relaunch */
2963 [self setRestorable:NO];
2968 - (void)awakeFromNib
2970 [self setAcceptsMouseMovedEvents: YES];
2972 if (b_dark_interface)
2974 [self setBackgroundColor: [NSColor clearColor]];
2975 [self setOpaque: NO];
2977 [self setHasShadow:NO];
2978 [self setHasShadow:YES];
2982 - (IBAction)fullscreen:(id)sender
2984 [[VLCCoreInteraction sharedInstance] toggleFullscreen];
2987 - (void)performClose:(id)sender
2989 if (b_dark_interface || !b_video_deco)
2990 [[VLCMainWindow sharedInstance] performClose: sender];
2992 [super performClose: sender];
2995 - (void)performMiniaturize:(id)sender
2997 if (b_dark_interface || !b_video_deco)
2998 [self miniaturize: sender];
3000 [super performMiniaturize: sender];
3003 - (void)performZoom:(id)sender
3005 if (b_dark_interface || !b_video_deco)
3006 [self customZoom: sender];
3008 [super performZoom: sender];
3011 - (void)zoom:(id)sender
3013 if (b_dark_interface || !b_video_deco)
3014 [self customZoom: sender];
3016 [super zoom: sender];
3019 - (BOOL)canBecomeKeyWindow
3024 - (BOOL)validateMenuItem:(NSMenuItem *)menuItem
3026 SEL s_menuAction = [menuItem action];
3028 if ((s_menuAction == @selector(performClose:)) || (s_menuAction == @selector(performMiniaturize:)) || (s_menuAction == @selector(performZoom:)))
3031 return [super validateMenuItem:menuItem];
3035 * Given a proposed frame rectangle, return a modified version
3036 * which will fit inside the screen.
3038 * This method is based upon NSWindow.m, part of the GNUstep GUI Library, licensed under LGPLv2+.
3039 * Authors: Scott Christley <scottc@net-community.com>, Venkat Ajjanagadde <venkat@ocbi.com>,
3040 * Felipe A. Rodriguez <far@ix.netcom.com>, Richard Frith-Macdonald <richard@brainstorm.co.uk>
3041 * Copyright (C) 1996 Free Software Foundation, Inc.
3043 - (NSRect) customConstrainFrameRect: (NSRect)frameRect toScreen: (NSScreen*)screen
3045 NSRect screenRect = [screen visibleFrame];
3048 /* Move top edge of the window inside the screen */
3049 difference = NSMaxY (frameRect) - NSMaxY (screenRect);
3052 frameRect.origin.y -= difference;
3055 /* If the window is resizable, resize it (if needed) so that the
3056 bottom edge is on the screen or can be on the screen when the user moves
3058 difference = NSMaxY (screenRect) - NSMaxY (frameRect);
3059 if (_styleMask & NSResizableWindowMask)
3063 difference2 = screenRect.origin.y - frameRect.origin.y;
3064 difference2 -= difference;
3065 // Take in account the space between the top of window and the top of the
3066 // screen which can be used to move the bottom of the window on the screen
3067 if (difference2 > 0)
3069 frameRect.size.height -= difference2;
3070 frameRect.origin.y += difference2;
3073 /* Ensure that resizing doesn't makewindow smaller than minimum */
3074 difference2 = [self minSize].height - frameRect.size.height;
3075 if (difference2 > 0)
3077 frameRect.size.height += difference2;
3078 frameRect.origin.y -= difference2;
3088 Zooms the receiver. This method calls the delegate method
3089 windowShouldZoom:toFrame: to determine if the window should
3090 be allowed to zoom to full screen.
3092 * This method is based upon NSWindow.m, part of the GNUstep GUI Library, licensed under LGPLv2+.
3093 * Authors: Scott Christley <scottc@net-community.com>, Venkat Ajjanagadde <venkat@ocbi.com>,
3094 * Felipe A. Rodriguez <far@ix.netcom.com>, Richard Frith-Macdonald <richard@brainstorm.co.uk>
3095 * Copyright (C) 1996 Free Software Foundation, Inc.
3097 - (void) customZoom: (id)sender
3099 NSRect maxRect = [[self screen] visibleFrame];
3100 NSRect currentFrame = [self frame];
3102 if ([[self delegate] respondsToSelector: @selector(windowWillUseStandardFrame:defaultFrame:)])
3104 maxRect = [[self delegate] windowWillUseStandardFrame: self defaultFrame: maxRect];
3107 maxRect = [self customConstrainFrameRect: maxRect toScreen: [self screen]];
3109 // Compare the new frame with the current one
3110 if ((abs(NSMaxX(maxRect) - NSMaxX(currentFrame)) < DIST)
3111 && (abs(NSMaxY(maxRect) - NSMaxY(currentFrame)) < DIST)
3112 && (abs(NSMinX(maxRect) - NSMinX(currentFrame)) < DIST)
3113 && (abs(NSMinY(maxRect) - NSMinY(currentFrame)) < DIST))
3115 // Already in zoomed mode, reset user frame, if stored
3116 if ([self frameAutosaveName] != nil)
3118 [self setFrame: previousSavedFrame display: YES animate: YES];
3119 [self saveFrameUsingName: [self frameAutosaveName]];
3124 if ([self frameAutosaveName] != nil)
3126 [self saveFrameUsingName: [self frameAutosaveName]];
3127 previousSavedFrame = [self frame];
3130 [self setFrame: maxRect display: YES animate: YES];
3133 - (NSArray *)accessibilityAttributeNames
3135 if( !b_dark_interface )
3136 return [super accessibilityAttributeNames];
3138 static NSMutableArray *attributes = nil;
3139 if ( attributes == nil ) {
3140 attributes = [[super accessibilityAttributeNames] mutableCopy];
3141 NSArray *appendAttributes = [NSArray arrayWithObjects: NSAccessibilitySubroleAttribute,
3142 NSAccessibilityCloseButtonAttribute,
3143 NSAccessibilityMinimizeButtonAttribute,
3144 NSAccessibilityZoomButtonAttribute,
3147 for( NSString *attribute in appendAttributes )
3149 if( ![attributes containsObject:attribute] )
3150 [attributes addObject:attribute];
3156 - (id)accessibilityAttributeValue: (NSString*)o_attribute_name
3158 if( b_dark_interface )
3160 VLCMainWindowTitleView *o_tbv = [[VLCMainWindow sharedInstance] detachedTitlebarView];
3162 if( [o_attribute_name isEqualTo: NSAccessibilitySubroleAttribute] )
3163 return NSAccessibilityStandardWindowSubrole;
3165 if( [o_attribute_name isEqualTo: NSAccessibilityCloseButtonAttribute] )
3166 return [[o_tbv closeButton] cell];
3168 if( [o_attribute_name isEqualTo: NSAccessibilityMinimizeButtonAttribute] )
3169 return [[o_tbv minimizeButton] cell];
3171 if( [o_attribute_name isEqualTo: NSAccessibilityZoomButtonAttribute] )
3172 return [[o_tbv zoomButton] cell];
3175 return [super accessibilityAttributeValue: o_attribute_name];