/*****************************************************************************
* misc.m: code not specific to vlc
*****************************************************************************
- * Copyright (C) 2003-2005 the VideoLAN team
+ * Copyright (C) 2003-2007 the VideoLAN team
* $Id$
*
* Authors: Jon Lech Johansen <jon-vl@nanocrew.net>
#include "playlist.h"
#include "controls.h"
+/*****************************************************************************
+ * NSAnimation (VLCAdditions)
+ *
+ * Missing extension to NSAnimation
+ *****************************************************************************/
+
+@implementation NSAnimation (VLCAdditions)
+/* fake class attributes */
+static NSMapTable *VLCAdditions_userInfo = NULL;
+
++ (void)load
+{
+ /* init our fake object attribute */
+ VLCAdditions_userInfo = NSCreateMapTable(NSNonRetainedObjectMapKeyCallBacks, NSObjectMapValueCallBacks, 16);
+}
+
+- (void)dealloc
+{
+ NSMapRemove(VLCAdditions_userInfo, self);
+ [super dealloc];
+}
+
+- (void)setUserInfo: (void *)userInfo
+{
+ NSMapInsert(VLCAdditions_userInfo, self, (void*)userInfo);
+}
+
+- (void *)userInfo
+{
+ return NSMapGet(VLCAdditions_userInfo, self);
+}
+@end
+
+/*****************************************************************************
+ * NSScreen (VLCAdditions)
+ *
+ * Missing extension to NSScreen
+ *****************************************************************************/
+
+@implementation NSScreen (VLCAdditions)
+
+static NSMutableArray *blackoutWindows = NULL;
+
++ (void)load
+{
+ /* init our fake object attribute */
+ blackoutWindows = [[NSMutableArray alloc] initWithCapacity:1];
+}
+
++ (NSScreen *)screenWithDisplayID: (CGDirectDisplayID)displayID
+{
+ int i;
+
+ for( i = 0; i < [[NSScreen screens] count]; i++ )
+ {
+ NSScreen *screen = [[NSScreen screens] objectAtIndex: i];
+ if([screen displayID] == displayID)
+ return screen;
+ }
+ return nil;
+}
+
+- (BOOL)isMainScreen
+{
+ return ([self displayID] == [[[NSScreen screens] objectAtIndex:0] displayID]);
+}
+
+- (BOOL)isScreen: (NSScreen*)screen
+{
+ return ([self displayID] == [screen displayID]);
+}
+
+- (CGDirectDisplayID)displayID
+{
+ return (CGDirectDisplayID)_screenNumber;
+}
+
+- (void)blackoutOtherScreens
+{
+ unsigned int i;
+
+ /* Free our previous blackout window (follow blackoutWindow alloc strategy) */
+ [blackoutWindows makeObjectsPerformSelector:@selector(close)];
+ [blackoutWindows removeAllObjects];
+
+
+ for(i = 0; i < [[NSScreen screens] count]; i++)
+ {
+ NSScreen *screen = [[NSScreen screens] objectAtIndex: i];
+ VLCWindow *blackoutWindow;
+ NSRect screen_rect;
+
+ if([self isScreen: screen])
+ continue;
+
+ screen_rect = [screen frame];
+ screen_rect.origin.x = screen_rect.origin.y = 0.0f;
+
+ /* blackoutWindow alloc strategy
+ - The NSMutableArray blackoutWindows has the blackoutWindow references
+ - blackoutOtherDisplays is responsible for alloc/releasing its Windows
+ */
+ blackoutWindow = [[VLCWindow alloc] initWithContentRect: screen_rect styleMask: NSBorderlessWindowMask
+ backing: NSBackingStoreBuffered defer: NO screen: screen];
+ [blackoutWindow setBackgroundColor:[NSColor blackColor]];
+ [blackoutWindow setLevel: NSFloatingWindowLevel]; /* Disappear when Expose is triggered */
+
+ [blackoutWindow orderFront: self animate: YES];
+
+ [blackoutWindows addObject: blackoutWindow];
+ [blackoutWindow release];
+ }
+}
+
++ (void)unblackoutScreens
+{
+ unsigned int i;
+
+ for(i = 0; i < [blackoutWindows count]; i++)
+ {
+ VLCWindow *blackoutWindow = [blackoutWindows objectAtIndex: i];
+ [blackoutWindow closeAndAnimate: YES];
+ }
+}
+
+@end
+
+/*****************************************************************************
+ * VLCWindow
+ *
+ * Missing extension to NSWindow
+ *****************************************************************************/
+
+@implementation VLCWindow
+- (id)initWithContentRect:(NSRect)contentRect styleMask:(unsigned int)styleMask
+ backing:(NSBackingStoreType)backingType defer:(BOOL)flag
+{
+ self = [super initWithContentRect:contentRect styleMask:styleMask backing:backingType defer:flag];
+ if( self )
+ b_isset_canBecomeKeyWindow = NO;
+ return self;
+}
+- (void)setCanBecomeKeyWindow: (BOOL)canBecomeKey
+{
+ b_isset_canBecomeKeyWindow = YES;
+ b_canBecomeKeyWindow = canBecomeKey;
+}
+
+- (BOOL)canBecomeKeyWindow
+{
+ if(b_isset_canBecomeKeyWindow)
+ return b_canBecomeKeyWindow;
+
+ return [super canBecomeKeyWindow];
+}
+
+- (void)closeAndAnimate: (BOOL)animate
+{
+ NSInvocation *invoc;
+
+ if (!animate || MACOS_VERSION < 10.4f)
+ {
+ [super close];
+ return;
+ }
+
+ invoc = [NSInvocation invocationWithMethodSignature:[super methodSignatureForSelector:@selector(close)]];
+ [invoc setTarget: (id)super];
+
+ if (![self isVisible] || [self alphaValue] == 0.0)
+ {
+ [super close];
+ return;
+ }
+
+ [self orderOut: self animate: YES callback: invoc];
+}
+
+- (void)orderOut: (id)sender animate: (BOOL)animate
+{
+ NSInvocation *invoc = [NSInvocation invocationWithMethodSignature:[super methodSignatureForSelector:@selector(orderOut:)]];
+ [invoc setTarget: (id)super];
+ [invoc setArgument: sender atIndex: 0];
+ [self orderOut: sender animate: animate callback: invoc];
+}
+
+- (void)orderOut: (id)sender animate: (BOOL)animate callback:(NSInvocation *)callback
+{
+ NSViewAnimation *anim;
+ NSViewAnimation *current_anim;
+ NSMutableDictionary *dict;
+
+ if (!animate || MACOS_VERSION < 10.4f)
+ {
+ [self orderOut: sender];
+ return;
+ }
+
+ dict = [[NSMutableDictionary alloc] initWithCapacity:2];
+
+ [dict setObject:self forKey:NSViewAnimationTargetKey];
+
+ [dict setObject:NSViewAnimationFadeOutEffect forKey:NSViewAnimationEffectKey];
+ anim = [[NSViewAnimation alloc] initWithViewAnimations:[NSArray arrayWithObjects:dict, nil]];
+ [dict release];
+
+ [anim setAnimationBlockingMode:NSAnimationNonblocking];
+ [anim setDuration:0.9];
+ [anim setFrameRate:30];
+ [anim setUserInfo: callback];
+
+ @synchronized(self) {
+ current_anim = self->animation;
+
+ if ([[[current_anim viewAnimations] objectAtIndex:0] objectForKey: NSViewAnimationEffectKey] == NSViewAnimationFadeOutEffect && [current_anim isAnimating])
+ {
+ [anim release];
+ }
+ else
+ {
+ if (current_anim)
+ {
+ [current_anim stopAnimation];
+ [anim setCurrentProgress:1.0-[current_anim currentProgress]];
+ [current_anim release];
+ }
+ else
+ [anim setCurrentProgress:1.0 - [self alphaValue]];
+ self->animation = anim;
+ [self setDelegate: self];
+ [anim startAnimation];
+ }
+ }
+}
+
+- (void)orderFront: (id)sender animate: (BOOL)animate
+{
+ NSViewAnimation *anim;
+ NSViewAnimation *current_anim;
+ NSMutableDictionary *dict;
+
+ if (!animate || MACOS_VERSION < 10.4f)
+ {
+ [super orderFront: sender];
+ [self setAlphaValue: 1.0];
+ return;
+ }
+
+ if (![self isVisible])
+ {
+ [self setAlphaValue: 0.0];
+ [super orderFront: sender];
+ }
+ else if ([self alphaValue] == 1.0)
+ {
+ [super orderFront: self];
+ return;
+ }
+
+ dict = [[NSMutableDictionary alloc] initWithCapacity:2];
+
+ [dict setObject:self forKey:NSViewAnimationTargetKey];
+
+ [dict setObject:NSViewAnimationFadeInEffect forKey:NSViewAnimationEffectKey];
+ anim = [[NSViewAnimation alloc] initWithViewAnimations:[NSArray arrayWithObjects:dict, nil]];
+ [dict release];
+
+ [anim setAnimationBlockingMode:NSAnimationNonblocking];
+ [anim setDuration:0.5];
+ [anim setFrameRate:30];
+
+ @synchronized(self) {
+ current_anim = self->animation;
+
+ if ([[[current_anim viewAnimations] objectAtIndex:0] objectForKey: NSViewAnimationEffectKey] == NSViewAnimationFadeInEffect && [current_anim isAnimating])
+ {
+ [anim release];
+ }
+ else
+ {
+ if (current_anim)
+ {
+ [current_anim stopAnimation];
+ [anim setCurrentProgress:1.0 - [current_anim currentProgress]];
+ [current_anim release];
+ }
+ else
+ [anim setCurrentProgress:[self alphaValue]];
+ self->animation = anim;
+ [self setDelegate: self];
+ [self orderFront: sender];
+ [anim startAnimation];
+ }
+ }
+}
+
+- (void)animationDidEnd:(NSAnimation*)anim
+{
+ if ([self alphaValue] <= 0.0)
+ {
+ NSInvocation * invoc;
+ [super orderOut: nil];
+ [self setAlphaValue: 1.0];
+ if ((invoc = [anim userInfo]))
+ [invoc invoke];
+ }
+}
+@end
+
/*****************************************************************************
* VLCControllerWindow
*****************************************************************************/
- (BOOL)performKeyEquivalent:(NSEvent *)o_event
{
+ /* We indeed want to prioritize Cocoa key equivalent against libvlc,
+ so we perform the menu equivalent now. */
+ if([[NSApp mainMenu] performKeyEquivalent:o_event])
+ return TRUE;
+
return [[VLCMain sharedInstance] hasDefinedShortcutKey:o_event] ||
[(VLCControls *)[[VLCMain sharedInstance] getControls] keyEvent:o_event];
}
[super dealloc];
}
+#if GC_ENABLED
+- (void)finalize
+{
+ /* dealloc doesn't get called on 10.5 if GC is enabled, so we need to provide the basic functionality here */
+ [self unregisterDraggedTypes];
+ [super finalize];
+}
+#endif
+
- (void)awakeFromNib
{
- [self registerForDraggedTypes:[NSArray arrayWithObjects:NSTIFFPboardType,
+ [self registerForDraggedTypes:[NSArray arrayWithObjects:NSTIFFPboardType,
NSFilenamesPboardType, nil]];
}
- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
{
- if ((NSDragOperationGeneric & [sender draggingSourceOperationMask])
+ if ((NSDragOperationGeneric & [sender draggingSourceOperationMask])
== NSDragOperationGeneric)
{
return NSDragOperationGeneric;
[super dealloc];
}
+#if GC_ENABLED
+- (void)finalize
+{
+ /* dealloc doesn't get called on 10.5 if GC is enabled, so we need to provide the basic functionality here */
+ [self unregisterDraggedTypes];
+ [super finalize];
+}
+#endif
+
- (void)awakeFromNib
{
- [self registerForDraggedTypes:[NSArray arrayWithObjects:NSTIFFPboardType,
+ [self registerForDraggedTypes:[NSArray arrayWithObjects:NSTIFFPboardType,
NSFilenamesPboardType, nil]];
}
- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
{
- if ((NSDragOperationGeneric & [sender draggingSourceOperationMask])
+ if ((NSDragOperationGeneric & [sender draggingSourceOperationMask])
== NSDragOperationGeneric)
{
return NSDragOperationGeneric;
// Center knob in given rect
knobRect.origin.x += (int)((float)(knobRect.size.width - 7)/2.0);
knobRect.origin.y += (int)((float)(knobRect.size.height - 7)/2.0);
-
+
// Draw diamond
NSRectFillUsingOperation(NSMakeRect(knobRect.origin.x + 3, knobRect.origin.y + 6, 1, 1), NSCompositeSourceOver);
NSRectFillUsingOperation(NSMakeRect(knobRect.origin.x + 2, knobRect.origin.y + 5, 3, 1), NSCompositeSourceOver);
NSRectClip(NSZeroRect);
[super drawRect:rect];
[[NSGraphicsContext currentContext] restoreGraphicsState];
-
+
// Full size
rect = [self bounds];
int diff = (int)(([[self cell] knobThickness] - 7.0)/2.0) - 1;
rect.origin.y += diff;
rect.size.width -= 2*diff-2;
rect.size.height -= 2*diff;
-
+
// Draw dark
NSRect knobRect = [[self cell] knobRectFlipped:NO];
[[[NSColor blackColor] colorWithAlphaComponent:0.6] set];
_drawFrameInRect(rect);
_drawKnobInRect(knobRect);
-
+
// Draw shadow
[[[NSColor blackColor] colorWithAlphaComponent:0.1] set];
rect.origin.x++;
[newCell setAction:[oldCell action]];
[newCell setControlSize:[oldCell controlSize]];
[newCell setType:[oldCell type]];
- [newCell setState:[oldCell state]];
+ [newCell setState:[oldCell state]];
[newCell setAllowsTickMarkValuesOnly:[oldCell allowsTickMarkValuesOnly]];
[newCell setAltIncrementValue:[oldCell altIncrementValue]];
[newCell setControlTint:[oldCell controlTint]];
[[self controlView] lockFocus];
[knob compositeToPoint:NSMakePoint( knob_rect.origin.x + 1,
- knob_rect.origin.y + knob_rect.size.height -2 )
+ knob_rect.origin.y + knob_rect.size.height -2 )
operation:NSCompositeSourceOver];
[[self controlView] unlockFocus];
}
-- (void)stopTracking:(NSPoint)lastPoint at:(NSPoint)stopPoint inView:
+- (void)stopTracking:(NSPoint)lastPoint at:(NSPoint)stopPoint inView:
(NSView *)controlView mouseIsUp:(BOOL)flag
{
b_mouse_down = NO;