Commit 87fe9845 authored by Pierre d'Herbemont's avatar Pierre d'Herbemont
Browse files

MacOSX/VLC_app: port the fullscreen zoom and the fspanel from gui/macosx to VLC_app.

parent ff7830bb
......@@ -6,6 +6,8 @@
* $Id$
*
* Authors: Pierre d'Herbemont <pdherbemont # videolan.org>
* Felix Kühne <fkuehne at videolan dot org>
* Jérôme Decoodt <djc at videolan dot org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -24,20 +26,33 @@
#import <Cocoa/Cocoa.h>
/*****************************************************************************
* NSIndexPath (VLCAppAddition)
*****************************************************************************/
@interface NSIndexPath (VLCAppAddition)
- (NSIndexPath *)indexPathByRemovingFirstIndex;
- (NSUInteger)lastIndex;
@end
/*****************************************************************************
* NSArray (VLCAppAddition)
*****************************************************************************/
@interface NSArray (VLCAppAddition)
- (id)objectAtIndexPath:(NSIndexPath *)path withNodeKeyPath:(NSString *)nodeKeyPath;
@end
/*****************************************************************************
* NSView (VLCAppAdditions)
*****************************************************************************/
@interface NSView (VLCAppAdditions)
- (void)moveSubviewsToVisible;
@end
/* Split view that supports slider animation */
/*****************************************************************************
* VLCOneSplitView
*
* Missing functionality to a one-split view
*****************************************************************************/
@interface VLCOneSplitView : NSSplitView
{
BOOL fixedCursorDuringResize;
......@@ -46,3 +61,64 @@
- (float)sliderPosition;
- (void)setSliderPosition:(float)newPosition;
@end
/*****************************************************************************
* NSScreen (VLCAdditions)
*
* Missing extension to NSScreen
*****************************************************************************/
@interface NSScreen (VLCAdditions)
+ (NSScreen *)screenWithDisplayID: (CGDirectDisplayID)displayID;
- (BOOL)isMainScreen;
- (BOOL)isScreen: (NSScreen*)screen;
- (CGDirectDisplayID)displayID;
- (void)blackoutOtherScreens;
+ (void)unblackoutScreens;
@end
/*****************************************************************************
* VLCWindow
*
* Missing extension to NSWindow (Used only when needing setCanBecomeKeyWindow)
*****************************************************************************/
@interface VLCWindow : NSWindow
{
BOOL canBecomeKeyWindow;
BOOL isset_canBecomeKeyWindow;
}
- (void)setCanBecomeKeyWindow: (BOOL)canBecomeKey;
@end
/*****************************************************************************
* VLCImageCustomizedSlider
*
* Slider personalized by backgroundImage and knobImage
*****************************************************************************/
@interface VLCImageCustomizedSlider : NSSlider
{
NSImage * knobImage;
NSImage * backgroundImage;
}
@property (retain) NSImage * knobImage;
@property (retain) NSImage * backgroundImage;
- (void)drawKnobInRect: (NSRect)knobRect;
- (void)drawBackgroundInRect: (NSRect)knobRect;
- (void)drawRect: (NSRect)rect;
@end
/*****************************************************************************
* NSImageView (VLCAppAdditions)
*
* Make the image view move the window by mouse down by default
*****************************************************************************/
@interface NSImageView (VLCAppAdditions)
- (void)mouseDownCanMoveWindow;
@end
......@@ -6,6 +6,8 @@
* $Id$
*
* Authors: Pierre d'Herbemont <pdherbemont # videolan.org>
* Felix Kühne <fkuehne at videolan dot org>
* Jérôme Decoodt <djc at videolan dot org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -123,3 +125,205 @@
}
@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];
[blackoutWindows addObject: blackoutWindow];
[blackoutWindow release];
}
}
+ (void)unblackoutScreens
{
unsigned int i;
for(i = 0; i < [blackoutWindows count]; i++)
{
VLCWindow *blackoutWindow = [blackoutWindows objectAtIndex: i];
[blackoutWindow close];
}
}
@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 )
isset_canBecomeKeyWindow = NO;
return self;
}
- (void)setCanBecomeKeyWindow: (BOOL)canBecomeKey
{
isset_canBecomeKeyWindow = YES;
canBecomeKeyWindow = canBecomeKey;
}
- (BOOL)canBecomeKeyWindow
{
if(isset_canBecomeKeyWindow)
return canBecomeKeyWindow;
return [super canBecomeKeyWindow];
}
@end
/*****************************************************************************
* VLCImageCustomizedSlider
*
* Slider personalized by backgroundImage and knobImage
*****************************************************************************/
@implementation VLCImageCustomizedSlider
@synthesize backgroundImage;
@synthesize knobImage;
- (id)initWithFrame:(NSRect)frame
{
if(self = [super initWithFrame:frame])
{
knobImage = nil;
backgroundImage = nil;
}
return self;
}
- (void)dealloc
{
[knobImage release];
[knobImage release];
[super dealloc];
}
- (void)drawKnobInRect:(NSRect) knobRect
{
NSRect imageRect;
imageRect.size = [self.knobImage size];
imageRect.origin.x = 0;
imageRect.origin.y = 0;
knobRect.origin.x += (knobRect.size.width - imageRect.size.width) / 2;
knobRect.origin.y += (knobRect.size.width - imageRect.size.width) / 2;
knobRect.size.width = imageRect.size.width;
knobRect.size.height = imageRect.size.height;
[self.knobImage drawInRect:knobRect fromRect:imageRect operation:NSCompositeSourceOver fraction:1];
}
- (void)drawBackgroundInRect:(NSRect) drawRect
{
NSRect imageRect = drawRect;
imageRect.origin.y += ([self.backgroundImage size].height - [self bounds].size.height ) / 2;
[self.backgroundImage drawInRect:drawRect fromRect:imageRect operation:NSCompositeSourceOver fraction:1];
}
- (void)drawRect:(NSRect)rect
{
/* Draw default to make sure the slider behaves correctly */
[[NSGraphicsContext currentContext] saveGraphicsState];
NSRectClip(NSZeroRect);
[super drawRect:rect];
[[NSGraphicsContext currentContext] restoreGraphicsState];
if( self.backgroundImage )
[self drawBackgroundInRect: rect];
if( self.knobImage )
{
NSRect knobRect = [[self cell] knobRectFlipped:NO];
[[[NSColor blackColor] colorWithAlphaComponent:0.6] set];
[self drawKnobInRect: knobRect];
}
}
@end
/*****************************************************************************
* NSImageView (VLCAppAdditions)
*
* Make the image view move the window by mouse down by default
*****************************************************************************/
@implementation NSImageView (VLCAppAdditions)
- (void)mouseDownCanMoveWindow
{
return YES;
}
@end
......@@ -201,6 +201,14 @@
{
return [NSSet setWithObjects:@"state", @"playing", @"canPause", nil];
}
+ (NSSet *)keyPathsForValuesAffectingStateAsFullScreenButtonImage
{
return [NSSet setWithObjects:@"state", @"playing", @"canPause", nil];
}
+ (NSSet *)keyPathsForValuesAffectingStateAsFullScreenButtonAlternateImage
{
return [NSSet setWithObjects:@"state", @"playing", @"canPause", nil];
}
- (NSString *)description
{
......@@ -229,4 +237,25 @@
else
return [NSImage imageNamed:@"play_blue.png"];
}
- (NSImage *)stateAsFullScreenButtonImage
{
if([self state] == VLCMediaPlayerStatePlaying && [self canPause])
return [NSImage imageNamed:@"fs_pause.png"];
else if( [self state] == VLCMediaPlayerStatePlaying )
return [NSImage imageNamed:@"fs_stop.png"];
else
return [NSImage imageNamed:@"fs_play.png"];
}
- (NSImage *)stateAsFullScreenButtonAlternateImage
{
if([self state] == VLCMediaPlayerStatePlaying && [self canPause])
return [NSImage imageNamed:@"fs_pause_highlight.png"];
else if( [self state] == VLCMediaPlayerStatePlaying )
return [NSImage imageNamed:@"fs_stop_highlight.png"];
else
return [NSImage imageNamed:@"fs_play_highlight.png"];
}
@end
......@@ -25,6 +25,7 @@
#import <QuartzCore/QuartzCore.h>
#import <VLCKit/VLCKit.h>
#import "VLCAppAdditions.h"
@interface VLCBrowsableVideoView : VLCVideoView {
BOOL menuDisplayed;
......@@ -43,6 +44,12 @@
/* Actions on non-node items*/
id target;
SEL action;
/* FullScreenTransition */
VLCWindow * fullScreenWindow;
NSViewAnimation * fullScreenAnim1;
NSViewAnimation * fullScreenAnim2;
NSView * tempFullScreenView;
}
/* Binds an nsarray to that property. But don't forget the set the access keys. */
......
/*****************************************************************************
* VLCBrowsableVideoView.h: VideoView subclasses that allow fullscreen
* VLCBrowsableVideoView.h: VideoView subclasses that allow fullScreen
* browsing
*****************************************************************************
* Copyright (C) 2007 Pierre d'Herbemont
......@@ -23,6 +23,9 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
/* DisableScreenUpdates, SetSystemUIMode, ... */
#import <QuickTime/QuickTime.h>
#import "VLCBrowsableVideoView.h"
#import "VLCAppAdditions.h"
......@@ -47,6 +50,16 @@
@end
@interface VLCBrowsableVideoView (FullScreenTransition)
- (void)hasEndedFullScreen;
- (void)hasBecomeFullScreen;
- (void)enterFullScreen:(NSScreen *)screen;
- (void)leaveFullScreen;
- (void)leaveFullScreenAndFadeOut: (BOOL)fadeout;
@end
/******************************************************************************
* VLCBrowsableVideoView
*/
......@@ -72,7 +85,7 @@
- (BOOL)fullScreen
{
return [super isInFullScreenMode];
return [self isInFullScreenMode];
}
- (void)setFullScreen:(BOOL)newFullScreen
......@@ -82,11 +95,13 @@
if( newFullScreen )
{
[super enterFullScreenMode:[[self window] screen] withOptions:nil];
[self enterFullScreenMode:[[self window] screen] withOptions:
[NSDictionary dictionaryWithObject: [NSNumber numberWithInt:1]
forKey: NSFullScreenModeWindowLevel]];
}
else
{
[super exitFullScreenModeWithOptions:nil];
[self exitFullScreenModeWithOptions:nil];
}
}
......@@ -101,11 +116,20 @@
selectionLayer = backLayer = nil;
menuLayer = nil;
selectedPath = [[NSIndexPath alloc] init];
tempFullScreenView = [[NSView alloc] init];
fullScreen = NO;
/* Observe our bindings */
//[self displayMenu];
//[self changeSelectedIndex:0];
}
- (void)dealloc
{
[tempFullScreenView release];
[selectedPath release];
[super dealloc];
}
/* Hiding/Displaying the menu */
- (void)hideMenu
......@@ -206,6 +230,23 @@
[super keyDown: theEvent];
}
- (void)enterFullScreenMode:(NSScreen *)screen withOptions:(NSDictionary *)options
{
[self enterFullScreen: screen];
}
- (void)exitFullScreenModeWithOptions:(NSDictionary *)options
{
[self leaveFullScreen];
}
- (BOOL)isInFullScreenMode
{
return fullScreen;
}
@end
/******************************************************************************
......@@ -430,4 +471,288 @@
menuLayer = layer;
selectionLayer = nil;
}
@end
\ No newline at end of file
@end
@implementation VLCBrowsableVideoView (FullScreenTransition)
- (void)enterFullScreen:(NSScreen *)screen
{
NSMutableDictionary *dict1,*dict2;
NSRect screenRect;
NSRect aRect;
screenRect = [screen frame];
[NSCursor setHiddenUntilMouseMoves: YES];
/* Only create the o_fullScreen_window if we are not in the middle of the zooming animation */
if (!fullScreenWindow)
{
/* We can't change the styleMask of an already created NSWindow, so we create an other window, and do eye catching stuff */
aRect = [[self superview] convertRect: [self frame] toView: nil]; /* Convert to Window base coord */
aRect.origin.x += [[self window] frame].origin.x;
aRect.origin.y += [[self window] frame].origin.y;
fullScreenWindow = [[VLCWindow alloc] initWithContentRect:aRect styleMask: NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:YES];
[fullScreenWindow setBackgroundColor: [NSColor blackColor]];
[fullScreenWindow setCanBecomeKeyWindow: YES];
if (![[self window] isVisible] || [[self window] alphaValue] == 0.0 || [self isHiddenOrHasHiddenAncestor] )
{
/* We don't animate if we are not visible or if we are running on
* Mac OS X <10.4 which doesn't support NSAnimation, instead we
* simply fade the display */
CGDisplayFadeReservationToken token;
[fullScreenWindow setFrame:screenRect display:NO];
CGAcquireDisplayFadeReservation(kCGMaxDisplayReservationInterval, &token);
CGDisplayFade( token, 0.3, kCGDisplayBlendNormal, kCGDisplayBlendSolidColor, 0, 0, 0, YES );
if ([screen isMainScreen])
SetSystemUIMode( kUIModeAllHidden, kUIOptionAutoShowMenuBar);
[self retain];
[[self superview] replaceSubview:self with:tempFullScreenView];
[tempFullScreenView setFrame:[self frame]];
[fullScreenWindow setContentView:self];
[fullScreenWindow makeKeyAndOrderFront:self];
[self release];
[[tempFullScreenView window] orderOut: self];
CGDisplayFade( token, 0.5, kCGDisplayBlendSolidColor, kCGDisplayBlendNormal, 0, 0, 0, NO );
CGReleaseDisplayFadeReservation( token);
[self hasBecomeFullScreen];
return;
}
/* Make sure we don't see the o_view disappearing of the screen during this operation */
DisableScreenUpdates();
[self retain]; /* Removing from a view, make sure we won't be released */
/* Make sure our layer won't disappear */
CALayer * layer = [[self layer] retain];
id alayoutManager = layer.layoutManager;
[[self superview] replaceSubview:self with:tempFullScreenView];
[tempFullScreenView setFrame:[self frame]];
[fullScreenWindow setContentView:self];
[self setWantsLayer:YES];
[self setLayer:layer];
layer.layoutManager = alayoutManager;
[fullScreenWindow makeKeyAndOrderFront:self];
EnableScreenUpdates();
}
/* We are in fullScreen (and no animation is running) */
if (fullScreen)
{
/* Make sure we are hidden */
[[tempFullScreenView window] orderOut: self];
return;
}
if (fullScreenAnim1)
{
[fullScreenAnim1 stopAnimation];
[fullScreenAnim1 release];
}
if (fullScreenAnim2)
{
[fullScreenAnim2 stopAnimation];
[fullScreenAnim2 release];
}
if ([screen isMainScreen])
SetSystemUIMode( kUIModeAllHidden, kUIOptionAutoShowMenuBar);
dict1 = [[NSMutableDictionary alloc] initWithCapacity:2];
dict2 = [[NSMutableDictionary alloc] initWithCapacity:3];
[dict1 setObject:[tempFullScreenView window] forKey:NSViewAnimationTargetKey];
[dict1 setObject:NSViewAnimationFadeOutEffect forKey:NSViewAnimationEffectKey];
[dict2 setObject:fullScreenWindow forKey:NSViewAnimationTargetKey];
[dict2 setObject:[NSValue valueWithRect:[fullScreenWindow frame]] forKey:NSViewAnimationStartFrameKey];
[dict2 setObject:[NSValue valueWithRect:screenRect] forKey:NSViewAnimationEndFrameKey];
/* Strategy with NSAnimation allocation:
- Keep at most 2 animation at a time