diff options
Diffstat (limited to 'src/SFML/Window/OSX/SFOpenGLView.mm')
-rw-r--r-- | src/SFML/Window/OSX/SFOpenGLView.mm | 352 |
1 files changed, 352 insertions, 0 deletions
diff --git a/src/SFML/Window/OSX/SFOpenGLView.mm b/src/SFML/Window/OSX/SFOpenGLView.mm new file mode 100644 index 0000000..e8fca84 --- /dev/null +++ b/src/SFML/Window/OSX/SFOpenGLView.mm @@ -0,0 +1,352 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2018 Marco Antognini (antognini.marco@gmail.com), +// Laurent Gomila (laurent@sfml-dev.org) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include <SFML/Window/OSX/WindowImplCocoa.hpp> +#include <SFML/System/Err.hpp> + +#import <SFML/Window/OSX/SFOpenGLView.h> +#import <SFML/Window/OSX/SFOpenGLView+mouse_priv.h> +#import <SFML/Window/OSX/SFSilentResponder.h> + + +//////////////////////////////////////////////////////////// +/// SFOpenGLView class: Privates Methods Declaration +/// +//////////////////////////////////////////////////////////// +@interface SFOpenGLView () + +//////////////////////////////////////////////////////////// +/// \brief Handle screen changed event +/// +//////////////////////////////////////////////////////////// +-(void)updateScaleFactor; + +//////////////////////////////////////////////////////////// +/// \brief Handle view resized event +/// +//////////////////////////////////////////////////////////// +-(void)viewDidEndLiveResize; + +//////////////////////////////////////////////////////////// +/// \brief Callback for focus event +/// +//////////////////////////////////////////////////////////// +-(void)windowDidBecomeKey:(NSNotification*)notification; + +//////////////////////////////////////////////////////////// +/// \brief Callback for unfocus event +/// +//////////////////////////////////////////////////////////// +-(void)windowDidResignKey:(NSNotification*)notification; + +//////////////////////////////////////////////////////////// +/// \brief Handle going in fullscreen mode +/// +//////////////////////////////////////////////////////////// +-(void)enterFullscreen; + +//////////////////////////////////////////////////////////// +/// \brief Handle exiting fullscreen mode +/// +//////////////////////////////////////////////////////////// +-(void)exitFullscreen; + +@end + +@implementation SFOpenGLView + +#pragma mark +#pragma mark SFOpenGLView's methods + +//////////////////////////////////////////////////////// +-(id)initWithFrame:(NSRect)frameRect +{ + return [self initWithFrame:frameRect fullscreen:NO]; +} + +//////////////////////////////////////////////////////// +-(id)initWithFrame:(NSRect)frameRect fullscreen:(BOOL)isFullscreen +{ + if ((self = [super initWithFrame:frameRect])) + { + [self setRequesterTo:0]; + [self enableKeyRepeat]; + + // Register for mouse move event + m_mouseIsIn = [self isMouseInside]; + NSUInteger opts = (NSTrackingActiveAlways | NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved | NSTrackingEnabledDuringMouseDrag); + m_trackingArea = [[NSTrackingArea alloc] initWithRect:[self bounds] + options:opts + owner:self + userInfo:nil]; + [self addTrackingArea:m_trackingArea]; + + m_fullscreen = isFullscreen; + m_scaleFactor = 1.0; // Default value; it will be updated in finishInit + m_cursorGrabbed = NO; + m_deltaXBuffer = 0; + m_deltaYBuffer = 0; + m_cursor = [NSCursor arrowCursor]; + + // Create a hidden text view for parsing key down event properly + m_silentResponder = [[SFSilentResponder alloc] init]; + m_hiddenTextView = [[NSTextView alloc] initWithFrame:NSZeroRect]; + [m_hiddenTextView setNextResponder:m_silentResponder]; + + // Request high resolution on high DPI displays + [self setWantsBestResolutionOpenGLSurface:YES]; + + // At that point, the view isn't attached to a window. We defer the rest of + // the initialization process to later. + } + + return self; +} + + +//////////////////////////////////////////////////////// +-(void)update +{ + // In order to prevent an infinite recursion when the window/view is + // resized to zero-height/width, we ignore update event when resizing. + if (![self inLiveResize]) { + [super update]; + } +} + + +//////////////////////////////////////////////////////// +-(void)finishInit +{ + // Register for window focus events + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(windowDidBecomeKey:) + name:NSWindowDidBecomeKeyNotification + object:[self window]]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(windowDidResignKey:) + name:NSWindowDidResignKeyNotification + object:[self window]]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(windowDidResignKey:) + name:NSWindowWillCloseNotification + object:[self window]]; + + // Register for changed screen and changed screen's profile events + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(updateScaleFactor) + name:NSWindowDidChangeScreenNotification + object:[self window]]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(updateScaleFactor) + name:NSWindowDidChangeScreenProfileNotification + object:[self window]]; + + // Now that we have a window, set up correctly the scale factor and cursor grabbing + [self updateScaleFactor]; + [self updateCursorGrabbed]; // update for fullscreen +} + + +//////////////////////////////////////////////////////// +-(void)setRequesterTo:(sf::priv::WindowImplCocoa*)requester +{ + m_requester = requester; +} + + +//////////////////////////////////////////////////////// +-(NSPoint)convertPointToScreen:(NSPoint)point +{ + NSRect rect = NSZeroRect; + rect.origin = point; + rect = [[self window] convertRectToScreen:rect]; + return rect.origin; +} + + +//////////////////////////////////////////////////////// +-(NSPoint)computeGlobalPositionOfRelativePoint:(NSPoint)point +{ + // Flip SFML coordinates to match window coordinates + point.y = [self frame].size.height - point.y; + + // Get the position of (x, y) in the coordinate system of the window. + point = [self convertPoint:point toView:self]; + point = [self convertPoint:point toView:nil]; // nil means window + + // Convert it to screen coordinates + point = [self convertPointToScreen:point]; + + // Flip screen coordinates to match CGDisplayMoveCursorToPoint referential. + const float screenHeight = [[[self window] screen] frame].size.height; + point.y = screenHeight - point.y; + + return point; +} + + +//////////////////////////////////////////////////////// +-(CGFloat)displayScaleFactor +{ + return m_scaleFactor; +} + + +//////////////////////////////////////////////////////// +-(void)updateScaleFactor +{ + NSWindow* window = [self window]; + NSScreen* screen = window ? [window screen] : [NSScreen mainScreen]; + CGFloat oldScaleFactor = m_scaleFactor; + m_scaleFactor = [screen backingScaleFactor]; + + // Send a resize event if the scaling factor changed + if ((m_scaleFactor != oldScaleFactor) && (m_requester != 0)) { + NSSize newSize = [self frame].size; + m_requester->windowResized(newSize.width, newSize.height); + } +} + + +//////////////////////////////////////////////////////// +-(void)viewDidEndLiveResize +{ + // We use viewDidEndLiveResize to notify the user ONCE + // only, when the resizing is finished. + // In a perfect world we would like to notify the user + // in live that the window is being resized. However, + // it seems impossible to forward to the user + // NSViewFrameDidChangeNotification before the resizing + // is done. Several notifications are emitted but they + // are all delivered after when the work is done. + + [super viewDidEndLiveResize]; + + // Update mouse internal state. + [self updateMouseState]; + [self updateCursorGrabbed]; + + // Update the OGL view to fit the new size. + [self update]; + + // Send an event + if (m_requester == 0) + return; + + // The new size + NSSize newSize = [self frame].size; + m_requester->windowResized(newSize.width, newSize.height); +} + +//////////////////////////////////////////////////////// +-(void)windowDidBecomeKey:(NSNotification*)notification +{ + (void)notification; + + [self updateCursorGrabbed]; + + if (m_requester) + m_requester->windowGainedFocus(); + + if (m_fullscreen) + [self enterFullscreen]; +} + + +//////////////////////////////////////////////////////// +-(void)windowDidResignKey:(NSNotification*)notification +{ + (void)notification; + + [self updateCursorGrabbed]; + + if (m_requester) + m_requester->windowLostFocus(); + + if (m_fullscreen) + [self exitFullscreen]; +} + + +//////////////////////////////////////////////////////// +-(void)enterFullscreen +{ + // Remove the tracking area first, + // just to be sure we don't add it twice! + [self removeTrackingArea:m_trackingArea]; + [self addTrackingArea:m_trackingArea]; + + // Fire an mouse entered event if needed + if (!m_mouseIsIn && (m_requester != 0)) + m_requester->mouseMovedIn(); + + // Update status + m_mouseIsIn = YES; +} + + +//////////////////////////////////////////////////////// +-(void)exitFullscreen +{ + [self removeTrackingArea:m_trackingArea]; + + // Fire an mouse left event if needed + if (m_mouseIsIn && (m_requester != 0)) + m_requester->mouseMovedOut(); + + // Update status + m_mouseIsIn = NO; +} + + +#pragma mark +#pragma mark Subclassing methods + + +//////////////////////////////////////////////////////// +-(void)dealloc +{ + // Unregister for window focus events + [[NSNotificationCenter defaultCenter] removeObserver:self]; + + // Unregister + [self removeTrackingArea:m_trackingArea]; + + // Release attributes + [m_hiddenTextView release]; + [m_silentResponder release]; + [m_trackingArea release]; + + [self setRequesterTo:0]; + + [super dealloc]; +} + + +@end |