1 /*****************************************************************************
2 * misc.m: code not specific to vlc
3 *****************************************************************************
4 * Copyright (C) 2003-2014 VLC authors and VideoLAN
7 * Authors: Jon Lech Johansen <jon-vl@nanocrew.net>
8 * Felix Paul Kühne <fkuehne at videolan dot org>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 *****************************************************************************/
25 #import "CompatibilityFixes.h"
27 #import "intf.h" /* VLCApplication */
28 #import "MainWindow.h"
29 #import "ControlsBar.h"
31 #import "CoreInteraction.h"
32 #import <CoreAudio/CoreAudio.h>
36 /*****************************************************************************
37 * NSSound (VLCAdditions)
39 * added code to change the system volume, needed for the apple remote code
40 * this is simplified code, which won't let you set the exact volume
41 * (that's what the audio output is for after all), but just the system volume
42 * in steps of 1/16 (matching the default AR or volume key implementation).
43 *****************************************************************************/
45 @implementation NSSound (VLCAdditions)
47 + (float)systemVolumeForChannel:(int)channel
49 AudioDeviceID i_device;
54 i_size = sizeof( i_device );
55 AudioObjectPropertyAddress deviceAddress = { kAudioHardwarePropertyDefaultOutputDevice, kAudioDevicePropertyScopeOutput, kAudioObjectPropertyElementMaster };
56 err = AudioObjectGetPropertyData( kAudioObjectSystemObject, &deviceAddress, 0, NULL, &i_size, &i_device );
58 msg_Warn( VLCIntf, "couldn't get main audio output device" );
62 AudioObjectPropertyAddress propertyAddress = { kAudioDevicePropertyVolumeScalar, kAudioDevicePropertyScopeOutput, channel };
63 i_size = sizeof( f_volume );
64 err = AudioObjectGetPropertyData(i_device, &propertyAddress, 0, NULL, &i_size, &f_volume);
66 msg_Warn( VLCIntf, "couldn't get volume value" );
73 + (bool)setSystemVolume:(float)f_volume forChannel:(int)i_channel
75 /* the following code will fail on S/PDIF devices. there is an easy work-around, but we'd like to match the OS behavior */
77 AudioDeviceID i_device;
82 i_size = sizeof( i_device );
83 AudioObjectPropertyAddress deviceAddress = { kAudioHardwarePropertyDefaultOutputDevice, kAudioDevicePropertyScopeOutput, kAudioObjectPropertyElementMaster };
84 err = AudioObjectGetPropertyData( kAudioObjectSystemObject, &deviceAddress, 0, NULL, &i_size, &i_device );
86 msg_Warn( VLCIntf, "couldn't get main audio output device" );
90 AudioObjectPropertyAddress propertyAddress = { kAudioDevicePropertyVolumeScalar, kAudioDevicePropertyScopeOutput, i_channel };
91 i_size = sizeof( f_volume );
92 err = AudioObjectIsPropertySettable( i_device, &propertyAddress, &b_writeable );
93 if (err != noErr || !b_writeable ) {
94 msg_Warn( VLCIntf, "we can't set the main audio devices' volume" );
97 err = AudioObjectSetPropertyData(i_device, &propertyAddress, 0, NULL, i_size, &f_volume);
102 + (void)increaseSystemVolume
104 float f_volume = [NSSound systemVolumeForChannel:1]; // we trust that mono is always available and that all channels got the same volume
105 f_volume += .0625; // 1/16 to match the OS
106 bool b_returned = YES;
108 /* since core audio doesn't provide a reasonable way to see how many channels we got, let's see how long we can do this */
109 for (NSUInteger x = 1; b_returned ; x++)
110 b_returned = [NSSound setSystemVolume: f_volume forChannel:x];
113 + (void)decreaseSystemVolume
115 float f_volume = [NSSound systemVolumeForChannel:1]; // we trust that mono is always available and that all channels got the same volume
116 f_volume -= .0625; // 1/16 to match the OS
117 bool b_returned = YES;
119 /* since core audio doesn't provide a reasonable way to see how many channels we got, let's see how long we can do this */
120 for (NSUInteger x = 1; b_returned ; x++)
121 b_returned = [NSSound setSystemVolume: f_volume forChannel:x];
126 /*****************************************************************************
127 * NSAnimation (VLCAdditions)
129 * Missing extension to NSAnimation
130 *****************************************************************************/
132 @implementation NSAnimation (VLCAdditions)
133 /* fake class attributes */
134 static NSMapTable *VLCAdditions_userInfo = NULL;
138 /* init our fake object attribute */
139 VLCAdditions_userInfo = NSCreateMapTable(NSNonRetainedObjectMapKeyCallBacks, NSObjectMapValueCallBacks, 16);
144 NSMapRemove(VLCAdditions_userInfo, self);
148 - (void)setUserInfo: (void *)userInfo
150 NSMapInsert(VLCAdditions_userInfo, self, (void*)userInfo);
155 return NSMapGet(VLCAdditions_userInfo, self);
159 /*****************************************************************************
160 * NSScreen (VLCAdditions)
162 * Missing extension to NSScreen
163 *****************************************************************************/
165 @implementation NSScreen (VLCAdditions)
167 static NSMutableArray *blackoutWindows = NULL;
169 static bool b_old_spaces_style = YES;
173 /* init our fake object attribute */
174 blackoutWindows = [[NSMutableArray alloc] initWithCapacity:1];
176 if (OSX_MAVERICKS || OSX_YOSEMITE) {
177 NSUserDefaults *userDefaults = [[NSUserDefaults alloc] init];
178 [userDefaults addSuiteNamed:@"com.apple.spaces"];
179 /* this is system settings -> mission control -> monitors using different spaces */
180 NSNumber *o_span_displays = [userDefaults objectForKey:@"spans-displays"];
182 b_old_spaces_style = [o_span_displays boolValue];
183 [userDefaults release];
187 + (NSScreen *)screenWithDisplayID: (CGDirectDisplayID)displayID
189 NSUInteger count = [[NSScreen screens] count];
191 for ( NSUInteger i = 0; i < count; i++ ) {
192 NSScreen *screen = [[NSScreen screens] objectAtIndex:i];
193 if ([screen displayID] == displayID)
201 if (b_old_spaces_style)
202 return ([self displayID] == [[[NSScreen screens] objectAtIndex:0] displayID]);
209 NSRect screen_frame = [self frame];
210 NSRect screen_visible_frame = [self visibleFrame];
211 CGFloat f_menu_bar_thickness = [self hasMenuBar] ? [[NSStatusBar systemStatusBar] thickness] : 0.0;
213 BOOL b_found_dock = NO;
214 if (screen_visible_frame.size.width < screen_frame.size.width)
216 else if (screen_visible_frame.size.height + f_menu_bar_thickness < screen_frame.size.height)
222 - (BOOL)isScreen: (NSScreen*)screen
224 return ([self displayID] == [screen displayID]);
227 - (CGDirectDisplayID)displayID
229 return (CGDirectDisplayID)[[[self deviceDescription] objectForKey: @"NSScreenNumber"] intValue];
232 - (void)blackoutOtherScreens
234 /* Free our previous blackout window (follow blackoutWindow alloc strategy) */
235 [blackoutWindows makeObjectsPerformSelector:@selector(close)];
236 [blackoutWindows removeAllObjects];
238 NSUInteger screenCount = [[NSScreen screens] count];
239 for (NSUInteger i = 0; i < screenCount; i++) {
240 NSScreen *screen = [[NSScreen screens] objectAtIndex:i];
241 VLCWindow *blackoutWindow;
244 if ([self isScreen: screen])
247 screen_rect = [screen frame];
248 screen_rect.origin.x = screen_rect.origin.y = 0;
250 /* blackoutWindow alloc strategy
251 - The NSMutableArray blackoutWindows has the blackoutWindow references
252 - blackoutOtherDisplays is responsible for alloc/releasing its Windows
254 blackoutWindow = [[VLCWindow alloc] initWithContentRect: screen_rect styleMask: NSBorderlessWindowMask
255 backing: NSBackingStoreBuffered defer: NO screen: screen];
256 [blackoutWindow setBackgroundColor:[NSColor blackColor]];
257 [blackoutWindow setLevel: NSFloatingWindowLevel]; /* Disappear when Expose is triggered */
258 [blackoutWindow setReleasedWhenClosed:NO]; // window is released when deleted from array above
260 [blackoutWindow displayIfNeeded];
261 [blackoutWindow orderFront: self animate: YES];
263 [blackoutWindows addObject: blackoutWindow];
264 [blackoutWindow release];
266 [screen setFullscreenPresentationOptions];
270 + (void)unblackoutScreens
272 NSUInteger blackoutWindowCount = [blackoutWindows count];
274 for (NSUInteger i = 0; i < blackoutWindowCount; i++) {
275 VLCWindow *blackoutWindow = [blackoutWindows objectAtIndex:i];
276 [[blackoutWindow screen] setNonFullscreenPresentationOptions];
277 [blackoutWindow closeAndAnimate: YES];
281 - (void)setFullscreenPresentationOptions
283 NSApplicationPresentationOptions presentationOpts = [NSApp presentationOptions];
284 if ([self hasMenuBar])
285 presentationOpts |= NSApplicationPresentationAutoHideMenuBar;
286 if ([self hasMenuBar] || [self hasDock])
287 presentationOpts |= NSApplicationPresentationAutoHideDock;
288 [NSApp setPresentationOptions:presentationOpts];
291 - (void)setNonFullscreenPresentationOptions
293 NSApplicationPresentationOptions presentationOpts = [NSApp presentationOptions];
294 if ([self hasMenuBar])
295 presentationOpts &= (~NSApplicationPresentationAutoHideMenuBar);
296 if ([self hasMenuBar] || [self hasDock])
297 presentationOpts &= (~NSApplicationPresentationAutoHideDock);
298 [NSApp setPresentationOptions:presentationOpts];
303 /*****************************************************************************
305 *****************************************************************************/
307 @implementation VLCDropDisabledImageView
311 [self unregisterDraggedTypes];
316 /*****************************************************************************
318 *****************************************************************************/
320 @implementation VLCDragDropView
322 @synthesize dropHandler=_dropHandler;
323 @synthesize drawBorder;
325 - (id)initWithFrame:(NSRect)frame
327 self = [super initWithFrame:frame];
330 [self setDrawBorder:YES];
336 - (void)enablePlaylistItems
338 [self registerForDraggedTypes:[NSArray arrayWithObjects:NSFilenamesPboardType, @"VLCPlaylistItemPboardType", nil]];
341 - (BOOL)mouseDownCanMoveWindow
348 [self unregisterDraggedTypes];
354 [self registerForDraggedTypes:[NSArray arrayWithObject:NSFilenamesPboardType]];
357 - (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
359 if ((NSDragOperationGeneric & [sender draggingSourceOperationMask]) == NSDragOperationGeneric) {
360 b_activeDragAndDrop = YES;
361 [self setNeedsDisplay:YES];
363 return NSDragOperationCopy;
366 return NSDragOperationNone;
369 - (void)draggingEnded:(id < NSDraggingInfo >)sender
371 b_activeDragAndDrop = NO;
372 [self setNeedsDisplay:YES];
375 - (void)draggingExited:(id < NSDraggingInfo >)sender
377 b_activeDragAndDrop = NO;
378 [self setNeedsDisplay:YES];
381 - (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender
386 - (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
390 if (_dropHandler && [_dropHandler respondsToSelector:@selector(performDragOperation:)])
391 b_returned = [_dropHandler performDragOperation: sender];
393 b_returned = [[VLCCoreInteraction sharedInstance] performDragOperation: sender];
395 [self setNeedsDisplay:YES];
399 - (void)concludeDragOperation:(id <NSDraggingInfo>)sender
401 [self setNeedsDisplay:YES];
404 - (void)drawRect:(NSRect)dirtyRect
406 if ([self drawBorder] && b_activeDragAndDrop) {
407 NSRect frameRect = [self bounds];
409 [[NSColor selectedControlColor] set];
410 NSFrameRectWithWidthUsingOperation(frameRect, 2., NSCompositeHighlight);
413 [super drawRect:dirtyRect];
419 /*****************************************************************************
421 *****************************************************************************/
422 @implementation MPSlider
424 void _drawKnobInRect(NSRect knobRect)
426 // Center knob in given rect
427 knobRect.origin.x += (int)((float)(knobRect.size.width - 7)/2.0);
428 knobRect.origin.y += (int)((float)(knobRect.size.height - 7)/2.0);
431 NSRectFillUsingOperation(NSMakeRect(knobRect.origin.x + 3, knobRect.origin.y + 6, 1, 1), NSCompositeSourceOver);
432 NSRectFillUsingOperation(NSMakeRect(knobRect.origin.x + 2, knobRect.origin.y + 5, 3, 1), NSCompositeSourceOver);
433 NSRectFillUsingOperation(NSMakeRect(knobRect.origin.x + 1, knobRect.origin.y + 4, 5, 1), NSCompositeSourceOver);
434 NSRectFillUsingOperation(NSMakeRect(knobRect.origin.x + 0, knobRect.origin.y + 3, 7, 1), NSCompositeSourceOver);
435 NSRectFillUsingOperation(NSMakeRect(knobRect.origin.x + 1, knobRect.origin.y + 2, 5, 1), NSCompositeSourceOver);
436 NSRectFillUsingOperation(NSMakeRect(knobRect.origin.x + 2, knobRect.origin.y + 1, 3, 1), NSCompositeSourceOver);
437 NSRectFillUsingOperation(NSMakeRect(knobRect.origin.x + 3, knobRect.origin.y + 0, 1, 1), NSCompositeSourceOver);
440 void _drawFrameInRect(NSRect frameRect)
443 NSRectFillUsingOperation(NSMakeRect(frameRect.origin.x, frameRect.origin.y, frameRect.size.width, 1), NSCompositeSourceOver);
444 NSRectFillUsingOperation(NSMakeRect(frameRect.origin.x, frameRect.origin.y + frameRect.size.height-1, frameRect.size.width, 1), NSCompositeSourceOver);
445 NSRectFillUsingOperation(NSMakeRect(frameRect.origin.x, frameRect.origin.y, 1, frameRect.size.height), NSCompositeSourceOver);
446 NSRectFillUsingOperation(NSMakeRect(frameRect.origin.x+frameRect.size.width-1, frameRect.origin.y, 1, frameRect.size.height), NSCompositeSourceOver);
449 - (void)drawRect:(NSRect)rect
451 // Draw default to make sure the slider behaves correctly
452 [[NSGraphicsContext currentContext] saveGraphicsState];
453 NSRectClip(NSZeroRect);
454 [super drawRect:rect];
455 [[NSGraphicsContext currentContext] restoreGraphicsState];
458 rect = [self bounds];
459 int diff = (int)(([[self cell] knobThickness] - 7.0)/2.0) - 1;
460 rect.origin.x += diff-1;
461 rect.origin.y += diff;
462 rect.size.width -= 2*diff-2;
463 rect.size.height -= 2*diff;
466 NSRect knobRect = [[self cell] knobRectFlipped:NO];
467 [[[NSColor blackColor] colorWithAlphaComponent:0.6] set];
468 _drawFrameInRect(rect);
469 _drawKnobInRect(knobRect);
472 [[[NSColor blackColor] colorWithAlphaComponent:0.1] set];
477 _drawFrameInRect(rect);
478 _drawKnobInRect(knobRect);
483 /*****************************************************************************
485 *****************************************************************************/
487 @implementation VLCProgressView : NSView
489 - (void)scrollWheel:(NSEvent *)o_event
492 CGFloat f_deltaY = [o_event deltaY];
493 CGFloat f_deltaX = [o_event deltaX];
495 if (!OSX_SNOW_LEOPARD && [o_event isDirectionInvertedFromDevice])
496 f_deltaX = -f_deltaX; // optimisation, actually double invertion of f_deltaY here
498 f_deltaY = -f_deltaY;
500 // positive for left / down, negative otherwise
501 CGFloat f_delta = f_deltaX + f_deltaY;
512 for (NSUInteger i = 0; i < (int)(f_abs/4.+1.) && f_abs > 0.05 ; i++) {
514 [[VLCCoreInteraction sharedInstance] forwardExtraShort];
516 [[VLCCoreInteraction sharedInstance] backwardExtraShort];
520 - (BOOL)acceptsFirstResponder
527 /*****************************************************************************
529 *****************************************************************************/
531 @implementation TimeLineSlider
535 if (config_GetInt( VLCIntf, "macosx-interfacestyle" )) {
536 o_knob_img = imageFromRes(@"progression-knob_dark");
539 o_knob_img = imageFromRes(@"progression-knob");
542 img_rect.size = [o_knob_img size];
543 img_rect.origin.x = img_rect.origin.y = 0;
548 [o_knob_img release];
552 - (CGFloat)knobPosition
554 NSRect knobRect = [[self cell] knobRectFlipped:NO];
555 knobRect.origin.x += knobRect.size.width / 2;
556 return knobRect.origin.x;
559 - (void)drawKnobInRect:(NSRect)knobRect
561 knobRect.origin.x += (knobRect.size.width - img_rect.size.width) / 2;
562 knobRect.size.width = img_rect.size.width;
563 knobRect.size.height = img_rect.size.height;
564 [o_knob_img drawInRect:knobRect fromRect:img_rect operation:NSCompositeSourceOver fraction:1];
567 - (void)drawRect:(NSRect)rect
569 [[(VLCVideoWindowCommon *)[self window] controlsBar] drawFancyGradientEffectForTimeSlider];
570 msleep(10000); //wait for the gradient to draw completely
572 /* Draw default to make sure the slider behaves correctly */
573 [[NSGraphicsContext currentContext] saveGraphicsState];
574 NSRectClip(NSZeroRect);
575 [super drawRect:rect];
576 [[NSGraphicsContext currentContext] restoreGraphicsState];
578 NSRect knobRect = [[self cell] knobRectFlipped:NO];
579 knobRect.origin.y+=1;
580 [self drawKnobInRect: knobRect];
585 /*****************************************************************************
586 * VLCVolumeSliderCommon
587 *****************************************************************************/
589 @implementation VLCVolumeSliderCommon : NSSlider
591 @synthesize usesBrightArtwork = _usesBrightArtwork;
593 - (void)scrollWheel:(NSEvent *)o_event
596 CGFloat f_deltaY = [o_event deltaY];
597 CGFloat f_deltaX = [o_event deltaX];
599 if (!OSX_SNOW_LEOPARD && [o_event isDirectionInvertedFromDevice])
600 f_deltaX = -f_deltaX; // optimisation, actually double invertion of f_deltaY here
602 f_deltaY = -f_deltaY;
604 // positive for left / down, negative otherwise
605 CGFloat f_delta = f_deltaX + f_deltaY;
615 for (NSUInteger i = 0; i < (int)(f_abs/4.+1.) && f_abs > 0.05 ; i++) {
617 [[VLCCoreInteraction sharedInstance] volumeUp];
619 [[VLCCoreInteraction sharedInstance] volumeDown];
623 - (void)drawFullVolumeMarker
625 CGFloat maxAudioVol = self.maxValue / AOUT_VOLUME_DEFAULT;
626 if (maxAudioVol < 1.)
629 NSColor *drawingColor;
630 // for bright artwork, a black color is used and vice versa
631 if (_usesBrightArtwork)
632 drawingColor = [[NSColor blackColor] colorWithAlphaComponent:.4];
634 drawingColor = [[NSColor whiteColor] colorWithAlphaComponent:.4];
636 NSBezierPath* bezierPath = [NSBezierPath bezierPath];
637 [self drawFullVolBezierPath:bezierPath];
638 [bezierPath closePath];
640 bezierPath.lineWidth = 1.;
641 [drawingColor setStroke];
645 - (CGFloat)fullVolumePos
647 CGFloat maxAudioVol = self.maxValue / AOUT_VOLUME_DEFAULT;
648 CGFloat sliderRange = [self frame].size.width - [self knobThickness];
649 CGFloat sliderOrigin = [self knobThickness] / 2.;
651 return 1. / maxAudioVol * sliderRange + sliderOrigin;
654 - (void)drawFullVolBezierPath:(NSBezierPath*)bezierPath
656 CGFloat fullVolPos = [self fullVolumePos];
657 [bezierPath moveToPoint:NSMakePoint(fullVolPos, [self frame].size.height - 3.)];
658 [bezierPath lineToPoint:NSMakePoint(fullVolPos, 2.)];
663 @implementation VolumeSliderCell
665 - (BOOL)continueTracking:(NSPoint)lastPoint at:(NSPoint)currentPoint inView:(NSView *)controlView
667 VLCVolumeSliderCommon *o_slider = (VLCVolumeSliderCommon *)controlView;
668 CGFloat fullVolumePos = [o_slider fullVolumePos] + 2.;
670 CGPoint snapToPoint = currentPoint;
671 if (ABS(fullVolumePos - currentPoint.x) <= 4.)
672 snapToPoint.x = fullVolumePos;
674 return [super continueTracking:lastPoint at:snapToPoint inView:controlView];
679 /*****************************************************************************
681 *****************************************************************************/
683 @implementation ITSlider
687 BOOL b_dark = config_GetInt( VLCIntf, "macosx-interfacestyle" );
689 img = imageFromRes(@"volume-slider-knob_dark");
691 img = imageFromRes(@"volume-slider-knob");
693 image_rect.size = [img size];
694 image_rect.origin.x = 0;
697 image_rect.origin.y = -1;
699 image_rect.origin.y = 0;
702 - (void)drawKnobInRect:(NSRect)knobRect
704 knobRect.origin.x += (knobRect.size.width - image_rect.size.width) / 2;
705 knobRect.size.width = image_rect.size.width;
706 knobRect.size.height = image_rect.size.height;
707 [img drawInRect:knobRect fromRect:image_rect operation:NSCompositeSourceOver fraction:1];
710 - (void)drawRect:(NSRect)rect
712 /* Draw default to make sure the slider behaves correctly */
713 [[NSGraphicsContext currentContext] saveGraphicsState];
714 NSRectClip(NSZeroRect);
715 [super drawRect:rect];
716 [[NSGraphicsContext currentContext] restoreGraphicsState];
718 [self drawFullVolumeMarker];
720 NSRect knobRect = [[self cell] knobRectFlipped:NO];
721 knobRect.origin.y+=2;
722 [self drawKnobInRect: knobRect];
727 /*****************************************************************************
728 * VLCTimeField implementation
729 *****************************************************************************
730 * we need this to catch our click-event in the controller window
731 *****************************************************************************/
733 @implementation VLCTimeField
736 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
737 NSDictionary *appDefaults = [NSDictionary dictionaryWithObjectsAndKeys:
738 @"NO", @"DisplayTimeAsTimeRemaining",
739 @"YES", @"DisplayFullscreenTimeAsTimeRemaining",
742 [defaults registerDefaults:appDefaults];
745 - (void)setRemainingIdentifier:(NSString *)o_string
747 o_remaining_identifier = o_string;
748 b_time_remaining = [[NSUserDefaults standardUserDefaults] boolForKey:o_remaining_identifier];
751 - (void)setAlignment:(NSTextAlignment)alignment
753 textAlignment = alignment;
754 [self setStringValue:[self stringValue]];
759 [o_string_shadow release];
763 - (void)setStringValue:(NSString *)string
765 if (!o_string_shadow) {
766 o_string_shadow = [[NSShadow alloc] init];
767 [o_string_shadow setShadowColor: [NSColor colorWithCalibratedWhite:1.0 alpha:0.5]];
768 [o_string_shadow setShadowOffset:NSMakeSize(0.0, -1.0)];
769 [o_string_shadow setShadowBlurRadius:0.0];
772 NSMutableAttributedString *o_attributed_string = [[NSMutableAttributedString alloc] initWithString:string attributes: nil];
773 NSUInteger i_stringLength = [string length];
775 [o_attributed_string addAttribute: NSShadowAttributeName value: o_string_shadow range: NSMakeRange(0, i_stringLength)];
776 [o_attributed_string setAlignment: textAlignment range: NSMakeRange(0, i_stringLength)];
777 [self setAttributedStringValue: o_attributed_string];
778 [o_attributed_string release];
781 - (void)mouseDown: (NSEvent *)ourEvent
783 if ( [ourEvent clickCount] > 1 )
784 [[[VLCMain sharedInstance] controls] goToSpecificTime: nil];
787 if (o_remaining_identifier) {
788 b_time_remaining = [[NSUserDefaults standardUserDefaults] boolForKey:o_remaining_identifier];
789 b_time_remaining = !b_time_remaining;
790 [[NSUserDefaults standardUserDefaults] setObject:(b_time_remaining ? @"YES" : @"NO") forKey:o_remaining_identifier];
792 b_time_remaining = !b_time_remaining;
797 - (BOOL)timeRemaining
799 if (o_remaining_identifier)
800 return [[NSUserDefaults standardUserDefaults] boolForKey:o_remaining_identifier];
802 return b_time_remaining;
807 /*****************************************************************************
808 * VLCMainWindowSplitView implementation
809 * comment 1 + 2 taken from NSSplitView.h (10.7 SDK)
810 *****************************************************************************/
811 @implementation VLCMainWindowSplitView : NSSplitView
812 /* Return the color of the dividers that the split view is drawing between subviews. The default implementation of this method returns [NSColor clearColor] for the thick divider style. It will also return [NSColor clearColor] for the thin divider style when the split view is in a textured window. All other thin dividers are drawn with a color that looks good between two white panes. You can override this method to change the color of dividers.
814 - (NSColor *)dividerColor
816 return [NSColor colorWithCalibratedRed:.60 green:.60 blue:.60 alpha:1.];
819 /* Return the thickness of the dividers that the split view is drawing between subviews. The default implementation returns a value that depends on the divider style. You can override this method to change the size of dividers.
821 - (CGFloat)dividerThickness
827 /*****************************************************************************
828 * VLCThreePartImageView interface
829 *****************************************************************************/
830 @implementation VLCThreePartImageView
834 [o_left_img release];
835 [o_middle_img release];
836 [o_right_img release];
841 - (void)setImagesLeft:(NSImage *)left middle: (NSImage *)middle right:(NSImage *)right
844 [o_left_img release];
846 [o_middle_img release];
848 [o_right_img release];
850 o_left_img = [left retain];
851 o_middle_img = [middle retain];
852 o_right_img = [right retain];
855 - (void)drawRect:(NSRect)rect
857 NSRect bnds = [self bounds];
858 NSDrawThreePartImage( bnds, o_left_img, o_middle_img, o_right_img, NO, NSCompositeSourceOver, 1, NO );
864 @implementation PositionFormatter
869 NSMutableCharacterSet *nonNumbers = [[[NSCharacterSet decimalDigitCharacterSet] invertedSet] mutableCopy];
870 [nonNumbers removeCharactersInString:@":"];
871 o_forbidden_characters = [nonNumbers copy];
872 [nonNumbers release];
879 [o_forbidden_characters release];
883 - (NSString*)stringForObjectValue:(id)obj
885 if([obj isKindOfClass:[NSString class]])
887 if([obj isKindOfClass:[NSNumber class]])
888 return [obj stringValue];
893 - (BOOL)getObjectValue:(id*)obj forString:(NSString*)string errorDescription:(NSString**)error
895 *obj = [[string copy] autorelease];
899 - (BOOL)isPartialStringValid:(NSString*)partialString newEditingString:(NSString**)newString errorDescription:(NSString**)error
901 if ([partialString rangeOfCharacterFromSet:o_forbidden_characters options:NSLiteralSearch].location != NSNotFound) {
910 @implementation NSView (EnableSubviews)
912 - (void)enableSubviews:(BOOL)b_enable
914 for (NSView *o_view in [self subviews]) {
915 [o_view enableSubviews:b_enable];
918 if ([o_view respondsToSelector:@selector(setEnabled:)]) {
919 [(NSControl *)o_view setEnabled:b_enable];
921 // also "enable / disable" text views
922 if ([o_view respondsToSelector:@selector(setTextColor:)]) {
923 if (b_enable == NO) {
924 [(NSTextField *)o_view setTextColor:[NSColor disabledControlTextColor]];
926 [(NSTextField *)o_view setTextColor:[NSColor controlTextColor]];
935 /*****************************************************************************
936 * VLCByteCountFormatter addition
937 *****************************************************************************/
939 @implementation VLCByteCountFormatter
941 + (NSString *)stringFromByteCount:(long long)byteCount countStyle:(NSByteCountFormatterCountStyle)countStyle
943 // Use native implementation on >= mountain lion
944 Class byteFormatterClass = NSClassFromString(@"NSByteCountFormatter");
945 if (byteFormatterClass && [byteFormatterClass respondsToSelector:@selector(stringFromByteCount:countStyle:)]) {
946 return [byteFormatterClass stringFromByteCount:byteCount countStyle:NSByteCountFormatterCountStyleFile];
950 float returnValue = 0.;
953 NSNumberFormatter *theFormatter = [[NSNumberFormatter alloc] init];
954 [theFormatter setLocale:[NSLocale currentLocale]];
955 [theFormatter setAllowsFloats:YES];
957 NSString *returnString = @"";
959 if (countStyle != NSByteCountFormatterCountStyleDecimal)
964 if (byteCount < 1000) {
965 returnValue = byteCount;
967 [theFormatter setMaximumFractionDigits:0];
971 if (byteCount < 1000000) {
972 returnValue = byteCount / devider;
974 [theFormatter setMaximumFractionDigits:0];
978 if (byteCount < 1000000000) {
979 returnValue = byteCount / devider / devider;
981 [theFormatter setMaximumFractionDigits:1];
985 [theFormatter setMaximumFractionDigits:2];
986 if (byteCount < 1000000000000) {
987 returnValue = byteCount / devider / devider / devider;
992 returnValue = byteCount / devider / devider / devider / devider;
996 returnString = [NSString stringWithFormat:@"%@ %@", [theFormatter stringFromNumber:[NSNumber numberWithFloat:returnValue]], suffix];
997 [theFormatter release];