1 /*****************************************************************************
2 * misc.m: code not specific to vlc
3 *****************************************************************************
4 * Copyright (C) 2003-2013 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 *****************************************************************************/
26 #import "intf.h" /* VLCApplication */
27 #import "MainWindow.h"
28 #import "ControlsBar.h"
30 #import "CoreInteraction.h"
31 #import <CoreAudio/CoreAudio.h>
35 /*****************************************************************************
36 * NSSound (VLCAdditions)
38 * added code to change the system volume, needed for the apple remote code
39 * this is simplified code, which won't let you set the exact volume
40 * (that's what the audio output is for after all), but just the system volume
41 * in steps of 1/16 (matching the default AR or volume key implementation).
42 *****************************************************************************/
44 @implementation NSSound (VLCAdditions)
46 + (float)systemVolumeForChannel:(int)channel
48 AudioDeviceID i_device;
53 i_size = sizeof( i_device );
54 AudioObjectPropertyAddress deviceAddress = { kAudioHardwarePropertyDefaultOutputDevice, kAudioDevicePropertyScopeOutput, kAudioObjectPropertyElementMaster };
55 err = AudioObjectGetPropertyData( kAudioObjectSystemObject, &deviceAddress, 0, NULL, &i_size, &i_device );
57 msg_Warn( VLCIntf, "couldn't get main audio output device" );
61 AudioObjectPropertyAddress propertyAddress = { kAudioDevicePropertyVolumeScalar, kAudioDevicePropertyScopeOutput, channel };
62 i_size = sizeof( f_volume );
63 err = AudioObjectGetPropertyData(i_device, &propertyAddress, 0, NULL, &i_size, &f_volume);
65 msg_Warn( VLCIntf, "couldn't get volume value" );
72 + (bool)setSystemVolume:(float)f_volume forChannel:(int)i_channel
74 /* the following code will fail on S/PDIF devices. there is an easy work-around, but we'd like to match the OS behavior */
76 AudioDeviceID i_device;
81 i_size = sizeof( i_device );
82 AudioObjectPropertyAddress deviceAddress = { kAudioHardwarePropertyDefaultOutputDevice, kAudioDevicePropertyScopeOutput, kAudioObjectPropertyElementMaster };
83 err = AudioObjectGetPropertyData( kAudioObjectSystemObject, &deviceAddress, 0, NULL, &i_size, &i_device );
85 msg_Warn( VLCIntf, "couldn't get main audio output device" );
89 AudioObjectPropertyAddress propertyAddress = { kAudioDevicePropertyVolumeScalar, kAudioDevicePropertyScopeOutput, i_channel };
90 i_size = sizeof( f_volume );
91 err = AudioObjectIsPropertySettable( i_device, &propertyAddress, &b_writeable );
92 if (err != noErr || !b_writeable ) {
93 msg_Warn( VLCIntf, "we can't set the main audio devices' volume" );
96 err = AudioObjectSetPropertyData(i_device, &propertyAddress, 0, NULL, i_size, &f_volume);
101 + (void)increaseSystemVolume
103 float f_volume = [NSSound systemVolumeForChannel:1]; // we trust that mono is always available and that all channels got the same volume
104 f_volume += .0625; // 1/16 to match the OS
105 bool b_returned = YES;
107 /* 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 */
108 for (NSUInteger x = 1; b_returned ; x++)
109 b_returned = [NSSound setSystemVolume: f_volume forChannel:x];
112 + (void)decreaseSystemVolume
114 float f_volume = [NSSound systemVolumeForChannel:1]; // we trust that mono is always available and that all channels got the same volume
115 f_volume -= .0625; // 1/16 to match the OS
116 bool b_returned = YES;
118 /* 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 */
119 for (NSUInteger x = 1; b_returned ; x++)
120 b_returned = [NSSound setSystemVolume: f_volume forChannel:x];
125 /*****************************************************************************
126 * NSAnimation (VLCAdditions)
128 * Missing extension to NSAnimation
129 *****************************************************************************/
131 @implementation NSAnimation (VLCAdditions)
132 /* fake class attributes */
133 static NSMapTable *VLCAdditions_userInfo = NULL;
137 /* init our fake object attribute */
138 VLCAdditions_userInfo = NSCreateMapTable(NSNonRetainedObjectMapKeyCallBacks, NSObjectMapValueCallBacks, 16);
143 NSMapRemove(VLCAdditions_userInfo, self);
147 - (void)setUserInfo: (void *)userInfo
149 NSMapInsert(VLCAdditions_userInfo, self, (void*)userInfo);
154 return NSMapGet(VLCAdditions_userInfo, self);
158 /*****************************************************************************
159 * NSScreen (VLCAdditions)
161 * Missing extension to NSScreen
162 *****************************************************************************/
164 @implementation NSScreen (VLCAdditions)
166 static NSMutableArray *blackoutWindows = NULL;
168 static bool b_old_spaces_style = YES;
172 /* init our fake object attribute */
173 blackoutWindows = [[NSMutableArray alloc] initWithCapacity:1];
176 NSUserDefaults *userDefaults = [[NSUserDefaults alloc] init];
177 [userDefaults addSuiteNamed:@"com.apple.spaces"];
178 /* this is system settings -> mission control -> monitors using different spaces */
179 NSNumber *o_span_displays = [userDefaults objectForKey:@"spans-displays"];
181 b_old_spaces_style = [o_span_displays boolValue];
182 [userDefaults release];
186 + (NSScreen *)screenWithDisplayID: (CGDirectDisplayID)displayID
188 NSUInteger count = [[NSScreen screens] count];
190 for ( NSUInteger i = 0; i < count; i++ ) {
191 NSScreen *screen = [[NSScreen screens] objectAtIndex:i];
192 if ([screen displayID] == displayID)
200 if (b_old_spaces_style)
201 return ([self displayID] == [[[NSScreen screens] objectAtIndex:0] displayID]);
208 NSRect screen_frame = [self frame];
209 NSRect screen_visible_frame = [self visibleFrame];
210 CGFloat f_menu_bar_thickness = [self hasMenuBar] ? [[NSStatusBar systemStatusBar] thickness] : 0.0;
212 BOOL b_found_dock = NO;
213 if (screen_visible_frame.size.width < screen_frame.size.width)
215 else if (screen_visible_frame.size.height + f_menu_bar_thickness < screen_frame.size.height)
221 - (BOOL)isScreen: (NSScreen*)screen
223 return ([self displayID] == [screen displayID]);
226 - (CGDirectDisplayID)displayID
228 return (CGDirectDisplayID)[[[self deviceDescription] objectForKey: @"NSScreenNumber"] intValue];
231 - (void)blackoutOtherScreens
233 /* Free our previous blackout window (follow blackoutWindow alloc strategy) */
234 [blackoutWindows makeObjectsPerformSelector:@selector(close)];
235 [blackoutWindows removeAllObjects];
237 NSUInteger screenCount = [[NSScreen screens] count];
238 for (NSUInteger i = 0; i < screenCount; i++) {
239 NSScreen *screen = [[NSScreen screens] objectAtIndex:i];
240 VLCWindow *blackoutWindow;
243 if ([self isScreen: screen])
246 screen_rect = [screen frame];
247 screen_rect.origin.x = screen_rect.origin.y = 0;
249 /* blackoutWindow alloc strategy
250 - The NSMutableArray blackoutWindows has the blackoutWindow references
251 - blackoutOtherDisplays is responsible for alloc/releasing its Windows
253 blackoutWindow = [[VLCWindow alloc] initWithContentRect: screen_rect styleMask: NSBorderlessWindowMask
254 backing: NSBackingStoreBuffered defer: NO screen: screen];
255 [blackoutWindow setBackgroundColor:[NSColor blackColor]];
256 [blackoutWindow setLevel: NSFloatingWindowLevel]; /* Disappear when Expose is triggered */
257 [blackoutWindow setReleasedWhenClosed:NO]; // window is released when deleted from array above
259 [blackoutWindow displayIfNeeded];
260 [blackoutWindow orderFront: self animate: YES];
262 [blackoutWindows addObject: blackoutWindow];
263 [blackoutWindow release];
265 [screen setFullscreenPresentationOptions];
269 + (void)unblackoutScreens
271 NSUInteger blackoutWindowCount = [blackoutWindows count];
273 for (NSUInteger i = 0; i < blackoutWindowCount; i++) {
274 VLCWindow *blackoutWindow = [blackoutWindows objectAtIndex:i];
275 [[blackoutWindow screen] setNonFullscreenPresentationOptions];
276 [blackoutWindow closeAndAnimate: YES];
280 - (void)setFullscreenPresentationOptions
282 NSApplicationPresentationOptions presentationOpts = [NSApp presentationOptions];
283 if ([self hasMenuBar])
284 presentationOpts |= NSApplicationPresentationAutoHideMenuBar;
285 if ([self hasMenuBar] || [self hasDock])
286 presentationOpts |= NSApplicationPresentationAutoHideDock;
287 [NSApp setPresentationOptions:presentationOpts];
290 - (void)setNonFullscreenPresentationOptions
292 NSApplicationPresentationOptions presentationOpts = [NSApp presentationOptions];
293 if ([self hasMenuBar])
294 presentationOpts &= (~NSApplicationPresentationAutoHideMenuBar);
295 if ([self hasMenuBar] || [self hasDock])
296 presentationOpts &= (~NSApplicationPresentationAutoHideDock);
297 [NSApp setPresentationOptions:presentationOpts];
302 /*****************************************************************************
304 *****************************************************************************/
306 @implementation VLCDropDisabledImageView
310 [self unregisterDraggedTypes];
315 /*****************************************************************************
317 *****************************************************************************/
319 @implementation VLCDragDropView
321 @synthesize dropHandler=_dropHandler;
323 - (void)enablePlaylistItems
325 [self registerForDraggedTypes:[NSArray arrayWithObjects:NSFilenamesPboardType, @"VLCPlaylistItemPboardType", nil]];
328 - (BOOL)mouseDownCanMoveWindow
335 [self unregisterDraggedTypes];
341 [self registerForDraggedTypes:[NSArray arrayWithObject:NSFilenamesPboardType]];
344 - (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
346 if ((NSDragOperationGeneric & [sender draggingSourceOperationMask]) == NSDragOperationGeneric) {
347 b_activeDragAndDrop = YES;
348 [self setNeedsDisplay:YES];
350 return NSDragOperationCopy;
353 return NSDragOperationNone;
356 - (void)draggingEnded:(id < NSDraggingInfo >)sender
358 b_activeDragAndDrop = NO;
359 [self setNeedsDisplay:YES];
362 - (void)draggingExited:(id < NSDraggingInfo >)sender
364 b_activeDragAndDrop = NO;
365 [self setNeedsDisplay:YES];
368 - (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender
373 - (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
377 if (_dropHandler && [_dropHandler respondsToSelector:@selector(performDragOperation:)])
378 b_returned = [_dropHandler performDragOperation: sender];
380 b_returned = [[VLCCoreInteraction sharedInstance] performDragOperation: sender];
382 [self setNeedsDisplay:YES];
386 - (void)concludeDragOperation:(id <NSDraggingInfo>)sender
388 [self setNeedsDisplay:YES];
391 - (void)drawRect:(NSRect)dirtyRect
394 if (b_activeDragAndDrop) {
395 NSRect frameRect = [self bounds];
397 [[NSColor selectedControlColor] set];
398 NSFrameRectWithWidthUsingOperation(frameRect, 2., NSCompositeHighlight);
401 [super drawRect:dirtyRect];
407 /*****************************************************************************
409 *****************************************************************************/
410 @implementation MPSlider
412 void _drawKnobInRect(NSRect knobRect)
414 // Center knob in given rect
415 knobRect.origin.x += (int)((float)(knobRect.size.width - 7)/2.0);
416 knobRect.origin.y += (int)((float)(knobRect.size.height - 7)/2.0);
419 NSRectFillUsingOperation(NSMakeRect(knobRect.origin.x + 3, knobRect.origin.y + 6, 1, 1), NSCompositeSourceOver);
420 NSRectFillUsingOperation(NSMakeRect(knobRect.origin.x + 2, knobRect.origin.y + 5, 3, 1), NSCompositeSourceOver);
421 NSRectFillUsingOperation(NSMakeRect(knobRect.origin.x + 1, knobRect.origin.y + 4, 5, 1), NSCompositeSourceOver);
422 NSRectFillUsingOperation(NSMakeRect(knobRect.origin.x + 0, knobRect.origin.y + 3, 7, 1), NSCompositeSourceOver);
423 NSRectFillUsingOperation(NSMakeRect(knobRect.origin.x + 1, knobRect.origin.y + 2, 5, 1), NSCompositeSourceOver);
424 NSRectFillUsingOperation(NSMakeRect(knobRect.origin.x + 2, knobRect.origin.y + 1, 3, 1), NSCompositeSourceOver);
425 NSRectFillUsingOperation(NSMakeRect(knobRect.origin.x + 3, knobRect.origin.y + 0, 1, 1), NSCompositeSourceOver);
428 void _drawFrameInRect(NSRect frameRect)
431 NSRectFillUsingOperation(NSMakeRect(frameRect.origin.x, frameRect.origin.y, frameRect.size.width, 1), NSCompositeSourceOver);
432 NSRectFillUsingOperation(NSMakeRect(frameRect.origin.x, frameRect.origin.y + frameRect.size.height-1, frameRect.size.width, 1), NSCompositeSourceOver);
433 NSRectFillUsingOperation(NSMakeRect(frameRect.origin.x, frameRect.origin.y, 1, frameRect.size.height), NSCompositeSourceOver);
434 NSRectFillUsingOperation(NSMakeRect(frameRect.origin.x+frameRect.size.width-1, frameRect.origin.y, 1, frameRect.size.height), NSCompositeSourceOver);
437 - (void)drawRect:(NSRect)rect
439 // Draw default to make sure the slider behaves correctly
440 [[NSGraphicsContext currentContext] saveGraphicsState];
441 NSRectClip(NSZeroRect);
442 [super drawRect:rect];
443 [[NSGraphicsContext currentContext] restoreGraphicsState];
446 rect = [self bounds];
447 int diff = (int)(([[self cell] knobThickness] - 7.0)/2.0) - 1;
448 rect.origin.x += diff-1;
449 rect.origin.y += diff;
450 rect.size.width -= 2*diff-2;
451 rect.size.height -= 2*diff;
454 NSRect knobRect = [[self cell] knobRectFlipped:NO];
455 [[[NSColor blackColor] colorWithAlphaComponent:0.6] set];
456 _drawFrameInRect(rect);
457 _drawKnobInRect(knobRect);
460 [[[NSColor blackColor] colorWithAlphaComponent:0.1] set];
465 _drawFrameInRect(rect);
466 _drawKnobInRect(knobRect);
471 /*****************************************************************************
473 *****************************************************************************/
475 @implementation VLCProgressView : NSView
477 - (void)scrollWheel:(NSEvent *)o_event
479 intf_thread_t * p_intf = VLCIntf;
481 CGFloat f_deltaY = [o_event deltaY];
482 CGFloat f_deltaX = [o_event deltaX];
484 if (!OSX_SNOW_LEOPARD && [o_event isDirectionInvertedFromDevice])
485 f_deltaX = -f_deltaX; // optimisation, actually double invertion of f_deltaY here
487 f_deltaY = -f_deltaY;
489 // positive for left / down, negative otherwise
490 CGFloat f_delta = f_deltaX + f_deltaY;
501 for (NSUInteger i = 0; i < (int)(f_abs/4.+1.) && f_abs > 0.05 ; i++) {
503 [[VLCCoreInteraction sharedInstance] forwardExtraShort];
505 [[VLCCoreInteraction sharedInstance] backwardExtraShort];
509 - (BOOL)acceptsFirstResponder
516 /*****************************************************************************
518 *****************************************************************************/
520 @implementation TimeLineSlider
524 if (config_GetInt( VLCIntf, "macosx-interfacestyle" )) {
525 o_knob_img = [NSImage imageNamed:@"progression-knob_dark"];
528 o_knob_img = [NSImage imageNamed:@"progression-knob"];
531 img_rect.size = [o_knob_img size];
532 img_rect.origin.x = img_rect.origin.y = 0;
537 [o_knob_img release];
541 - (CGFloat)knobPosition
543 NSRect knobRect = [[self cell] knobRectFlipped:NO];
544 knobRect.origin.x += knobRect.size.width / 2;
545 return knobRect.origin.x;
548 - (void)drawKnobInRect:(NSRect)knobRect
550 knobRect.origin.x += (knobRect.size.width - img_rect.size.width) / 2;
551 knobRect.size.width = img_rect.size.width;
552 knobRect.size.height = img_rect.size.height;
553 [o_knob_img drawInRect:knobRect fromRect:img_rect operation:NSCompositeSourceOver fraction:1];
556 - (void)drawRect:(NSRect)rect
558 [[(VLCVideoWindowCommon *)[self window] controlsBar] drawFancyGradientEffectForTimeSlider];
559 msleep(10000); //wait for the gradient to draw completely
561 /* Draw default to make sure the slider behaves correctly */
562 [[NSGraphicsContext currentContext] saveGraphicsState];
563 NSRectClip(NSZeroRect);
564 [super drawRect:rect];
565 [[NSGraphicsContext currentContext] restoreGraphicsState];
567 NSRect knobRect = [[self cell] knobRectFlipped:NO];
568 knobRect.origin.y+=1;
569 [self drawKnobInRect: knobRect];
574 /*****************************************************************************
575 * VLCVolumeSliderCommon
576 *****************************************************************************/
578 @implementation VLCVolumeSliderCommon : NSSlider
580 @synthesize usesBrightArtwork = _usesBrightArtwork;
582 - (void)scrollWheel:(NSEvent *)o_event
584 intf_thread_t * p_intf = VLCIntf;
586 CGFloat f_deltaY = [o_event deltaY];
587 CGFloat f_deltaX = [o_event deltaX];
589 if (!OSX_SNOW_LEOPARD && [o_event isDirectionInvertedFromDevice])
590 f_deltaX = -f_deltaX; // optimisation, actually double invertion of f_deltaY here
592 f_deltaY = -f_deltaY;
594 // positive for left / down, negative otherwise
595 CGFloat f_delta = f_deltaX + f_deltaY;
606 for (NSUInteger i = 0; i < (int)(f_abs/4.+1.) && f_abs > 0.05 ; i++) {
608 [[VLCCoreInteraction sharedInstance] volumeUp];
610 [[VLCCoreInteraction sharedInstance] volumeDown];
614 - (void)drawFullVolumeMarker
616 CGFloat maxAudioVol = self.maxValue / AOUT_VOLUME_DEFAULT;
617 if (maxAudioVol < 1.)
620 NSColor *drawingColor;
621 // for bright artwork, a black color is used and vice versa
622 if (_usesBrightArtwork)
623 drawingColor = [[NSColor blackColor] colorWithAlphaComponent:.4];
625 drawingColor = [[NSColor whiteColor] colorWithAlphaComponent:.4];
627 NSBezierPath* bezierPath = [NSBezierPath bezierPath];
628 [self drawFullVolBezierPath:bezierPath];
629 [bezierPath closePath];
631 bezierPath.lineWidth = 1.;
632 [drawingColor setStroke];
636 - (CGFloat)fullVolumePos
638 CGFloat maxAudioVol = self.maxValue / AOUT_VOLUME_DEFAULT;
639 CGFloat sliderRange = [self frame].size.width - [self knobThickness];
640 CGFloat sliderOrigin = [self knobThickness] / 2.;
642 return 1. / maxAudioVol * sliderRange + sliderOrigin;
645 - (void)drawFullVolBezierPath:(NSBezierPath*)bezierPath
647 CGFloat fullVolPos = [self fullVolumePos];
648 [bezierPath moveToPoint:NSMakePoint(fullVolPos, [self frame].size.height - 3.)];
649 [bezierPath lineToPoint:NSMakePoint(fullVolPos, 2.)];
654 @implementation VolumeSliderCell
656 - (BOOL)continueTracking:(NSPoint)lastPoint at:(NSPoint)currentPoint inView:(NSView *)controlView
658 VLCVolumeSliderCommon *o_slider = (VLCVolumeSliderCommon *)controlView;
659 CGFloat fullVolumePos = [o_slider fullVolumePos] + 2.;
661 CGPoint snapToPoint = currentPoint;
662 if (ABS(fullVolumePos - currentPoint.x) <= 4.)
663 snapToPoint.x = fullVolumePos;
665 return [super continueTracking:lastPoint at:snapToPoint inView:controlView];
670 /*****************************************************************************
672 *****************************************************************************/
674 @implementation ITSlider
678 BOOL b_dark = config_GetInt( VLCIntf, "macosx-interfacestyle" );
680 img = [NSImage imageNamed:@"volume-slider-knob_dark"];
682 img = [NSImage imageNamed:@"volume-slider-knob"];
684 image_rect.size = [img size];
685 image_rect.origin.x = 0;
688 image_rect.origin.y = -1;
690 image_rect.origin.y = 0;
693 - (void)drawKnobInRect:(NSRect)knobRect
695 knobRect.origin.x += (knobRect.size.width - image_rect.size.width) / 2;
696 knobRect.size.width = image_rect.size.width;
697 knobRect.size.height = image_rect.size.height;
698 [img drawInRect:knobRect fromRect:image_rect operation:NSCompositeSourceOver fraction:1];
701 - (void)drawRect:(NSRect)rect
703 /* Draw default to make sure the slider behaves correctly */
704 [[NSGraphicsContext currentContext] saveGraphicsState];
705 NSRectClip(NSZeroRect);
706 [super drawRect:rect];
707 [[NSGraphicsContext currentContext] restoreGraphicsState];
709 [self drawFullVolumeMarker];
711 NSRect knobRect = [[self cell] knobRectFlipped:NO];
712 knobRect.origin.y+=2;
713 [self drawKnobInRect: knobRect];
718 /*****************************************************************************
719 * VLCTimeField implementation
720 *****************************************************************************
721 * we need this to catch our click-event in the controller window
722 *****************************************************************************/
724 @implementation VLCTimeField
726 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
727 NSDictionary *appDefaults = [NSDictionary dictionaryWithObjectsAndKeys:
728 @"NO", @"DisplayTimeAsTimeRemaining",
729 @"YES", @"DisplayFullscreenTimeAsTimeRemaining",
732 [defaults registerDefaults:appDefaults];
735 - (id)initWithFrame:(NSRect)frameRect
737 if (self = [super initWithFrame:frameRect]) {
738 textAlignment = NSCenterTextAlignment;
739 o_remaining_identifier = @"";
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 isEqualToString: @""]) {
788 if ([[NSUserDefaults standardUserDefaults] boolForKey:o_remaining_identifier]) {
789 [[NSUserDefaults standardUserDefaults] setObject:@"NO" forKey:o_remaining_identifier];
790 b_time_remaining = NO;
792 [[NSUserDefaults standardUserDefaults] setObject:@"YES" forKey:o_remaining_identifier];
793 b_time_remaining = YES;
796 b_time_remaining = !b_time_remaining;
797 [[NSUserDefaults standardUserDefaults] setObject:(b_time_remaining ? @"YES" : @"NO") forKey:o_remaining_identifier];
802 - (BOOL)timeRemaining
804 if (![o_remaining_identifier isEqualToString: @""])
805 return [[NSUserDefaults standardUserDefaults] boolForKey:o_remaining_identifier];
807 return b_time_remaining;
812 /*****************************************************************************
813 * VLCMainWindowSplitView implementation
814 * comment 1 + 2 taken from NSSplitView.h (10.7 SDK)
815 *****************************************************************************/
816 @implementation VLCMainWindowSplitView : NSSplitView
817 /* 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.
819 - (NSColor *)dividerColor
821 return [NSColor colorWithCalibratedRed:.60 green:.60 blue:.60 alpha:1.];
824 /* 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.
826 - (CGFloat)dividerThickness
832 /*****************************************************************************
833 * VLCThreePartImageView interface
834 *****************************************************************************/
835 @implementation VLCThreePartImageView
839 [o_left_img release];
840 [o_middle_img release];
841 [o_right_img release];
846 - (void)setImagesLeft:(NSImage *)left middle: (NSImage *)middle right:(NSImage *)right
849 [o_left_img release];
851 [o_middle_img release];
853 [o_right_img release];
855 o_left_img = [left retain];
856 o_middle_img = [middle retain];
857 o_right_img = [right retain];
860 - (void)drawRect:(NSRect)rect
862 NSRect bnds = [self bounds];
863 NSDrawThreePartImage( bnds, o_left_img, o_middle_img, o_right_img, NO, NSCompositeSourceOver, 1, NO );
868 @implementation VLCThreePartDropView
870 - (BOOL)mouseDownCanMoveWindow
877 [self unregisterDraggedTypes];
883 [self registerForDraggedTypes:[NSArray arrayWithObject:NSFilenamesPboardType]];
886 - (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
888 if ((NSDragOperationGeneric & [sender draggingSourceOperationMask]) == NSDragOperationGeneric)
889 return NSDragOperationGeneric;
891 return NSDragOperationNone;
894 - (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender
899 - (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
902 b_returned = [[VLCCoreInteraction sharedInstance] performDragOperation: sender];
904 [self setNeedsDisplay:YES];
908 - (void)concludeDragOperation:(id <NSDraggingInfo>)sender
910 [self setNeedsDisplay:YES];
915 @implementation PositionFormatter
920 NSMutableCharacterSet *nonNumbers = [[[NSCharacterSet decimalDigitCharacterSet] invertedSet] mutableCopy];
921 [nonNumbers removeCharactersInString:@":"];
922 o_forbidden_characters = [nonNumbers copy];
923 [nonNumbers release];
930 [o_forbidden_characters release];
934 - (NSString*)stringForObjectValue:(id)obj
936 if([obj isKindOfClass:[NSString class]])
938 if([obj isKindOfClass:[NSNumber class]])
939 return [obj stringValue];
944 - (BOOL)getObjectValue:(id*)obj forString:(NSString*)string errorDescription:(NSString**)error
946 *obj = [[string copy] autorelease];
950 - (bool)isPartialStringValid:(NSString*)partialString newEditingString:(NSString**)newString errorDescription:(NSString**)error
952 if ([partialString rangeOfCharacterFromSet:o_forbidden_characters options:NSLiteralSearch].location != NSNotFound) {
962 @implementation NSView (EnableSubviews)
964 - (void)enableSubviews:(BOOL)b_enable
966 for (NSView *o_view in [self subviews]) {
967 [o_view enableSubviews:b_enable];
970 if ([o_view respondsToSelector:@selector(setEnabled:)]) {
971 [(NSControl *)o_view setEnabled:b_enable];
973 // also "enable / disable" text views
974 if ([o_view respondsToSelector:@selector(setTextColor:)]) {
975 if (b_enable == NO) {
976 [(NSTextField *)o_view setTextColor:[NSColor disabledControlTextColor]];
978 [(NSTextField *)o_view setTextColor:[NSColor controlTextColor]];