فهرست منبع

WIP: macOS port
- Moving all windowing operations to the main thread

Marko Pintera 7 سال پیش
والد
کامیت
30320c2eba

+ 21 - 9
Data/Raw/Engine/Shaders/ShadowProject.bsl

@@ -226,18 +226,30 @@ technique ShadowProject
 			// Every three gathers (one row), the values are accumulated to their corresponding row.
 			// Samples for individual gather operations are returned in counter-clockwise order, starting with lower left.
 			float2 rows[3];
-			[unroll]
-			for(int i = 0; i < 3; i++)
 			{
-				int y = -2 + i * 2;
-			
-				float4 left = getOcclusion(gShadowTex.GatherRed(gShadowSampler, sampleCenter, int2(-2, y)), sceneDepth);
-				float4 middle = getOcclusion(gShadowTex.GatherRed(gShadowSampler, sampleCenter, int2(0, y)), sceneDepth);
-				float4 right = getOcclusion(gShadowTex.GatherRed(gShadowSampler, sampleCenter, int2(2, y)), sceneDepth);
+				float4 left = getOcclusion(gShadowTex.GatherRed(gShadowSampler, sampleCenter, int2(-2, -2)), sceneDepth);
+				float4 middle = getOcclusion(gShadowTex.GatherRed(gShadowSampler, sampleCenter, int2(0, -2)), sceneDepth);
+				float4 right = getOcclusion(gShadowTex.GatherRed(gShadowSampler, sampleCenter, int2(2, -2)), sceneDepth);
 				
-				rows[i] = accumulateRows6x2(fraction.x, left, middle, right);
+				rows[0] = accumulateRows6x2(fraction.x, left, middle, right);
 			}
-			
+
+			{
+				float4 left = getOcclusion(gShadowTex.GatherRed(gShadowSampler, sampleCenter, int2(-2, 0)), sceneDepth);
+				float4 middle = getOcclusion(gShadowTex.GatherRed(gShadowSampler, sampleCenter, int2(0, 0)), sceneDepth);
+				float4 right = getOcclusion(gShadowTex.GatherRed(gShadowSampler, sampleCenter, int2(2, 0)), sceneDepth);
+
+				rows[1] = accumulateRows6x2(fraction.x, left, middle, right);
+			}
+
+			{
+				float4 left = getOcclusion(gShadowTex.GatherRed(gShadowSampler, sampleCenter, int2(-2, 2)), sceneDepth);
+				float4 middle = getOcclusion(gShadowTex.GatherRed(gShadowSampler, sampleCenter, int2(0, 2)), sceneDepth);
+				float4 right = getOcclusion(gShadowTex.GatherRed(gShadowSampler, sampleCenter, int2(2, 2)), sceneDepth);
+
+				rows[2] = accumulateRows6x2(fraction.x, left, middle, right);
+			}
+
 			// Accumulate all rows
 			float occlusionAccumulator;
 			occlusionAccumulator = rows[0].x * (1.0f - fraction.y);

+ 3 - 15
Source/BansheeCore/Platform/BsPlatform.h

@@ -274,25 +274,13 @@ namespace bs
 		/** Called during application start up from the sim thread. Must be called before any other operations are done. */
 		static void _startUp();
 
-		/**
-		 * Called once per frame from the sim thread.
-		 *
-		 * @note	Sim thread only.
-		 */
+		/** Called once per frame from the sim thread. */
 		static void _update();
 
-		/**
-		 * Called once per frame from the core thread.
-		 *
-		 * @note	Core thread only.
-		 */
+		/** Called once per frame from the core thread. */
 		static void _coreUpdate();
 
-		/**
-		 * Called during application shut down from the sim thread.
-		 *
-		 * @note	Sim thread only.
-		 */
+		/** Called during application shut down from the sim thread. */
 		static void _shutDown();
 
 		/**

+ 82 - 73
Source/BansheeCore/Private/MacOS/BsMacOSDropTarget.cpp

@@ -7,6 +7,7 @@
 #include "Math/BsRect2I.h"
 #include "Private/MacOS/BsMacOSDropTarget.h"
 #include "Private/MacOS/BsMacOSWindow.h"
+#include "CoreThread/BsCoreThread.h"
 
 namespace bs
 {
@@ -55,6 +56,64 @@ namespace bs
 
 	void CocoaDragAndDrop::update()
 	{
+		THROW_IF_CORE_THREAD
+
+		// First handle any queued registration/unregistration
+		{
+			Lock lock(sMutex);
+
+			for(auto& entry : sQueuedAreaOperations)
+			{
+				CocoaWindow* areaWindow;
+				entry.target->_getOwnerWindow()->getCustomAttribute("COCOA_WINDOW", &areaWindow);
+
+				switch(entry.type)
+				{
+				case DropAreaOpType::Register:
+					sDropAreas.push_back(DropArea(entry.target, entry.area));
+					areaWindow->_registerForDragAndDrop();
+					break;
+				case DropAreaOpType::Unregister:
+					// Remove any operations queued for this target
+					for(auto iter = sQueuedOperations.begin(); iter !=sQueuedOperations.end();)
+					{
+						if(iter->target == entry.target)
+							iter = sQueuedOperations.erase(iter);
+						else
+							++iter;
+					}
+
+					// Remove the area
+					{
+						auto iterFind = std::find_if(sDropAreas.begin(), sDropAreas.end(), [&](const DropArea& area)
+						{
+							return area.target == entry.target;
+						});
+
+						sDropAreas.erase(iterFind);
+					}
+
+					areaWindow->_unregisterForDragAndDrop();
+
+					break;
+				case DropAreaOpType::Update:
+				{
+					auto iterFind = std::find_if(sDropAreas.begin(), sDropAreas.end(), [&](const DropArea& area)
+					{
+						return area.target == entry.target;
+					});
+
+					if (iterFind != sDropAreas.end())
+						iterFind->area = entry.area;
+				}
+					break;
+				}
+			}
+
+			sQueuedAreaOperations.clear();
+		}
+
+		// Actually trigger events
 		Vector<DragAndDropOp> operations;
 
 		{
@@ -84,72 +143,16 @@ namespace bs
 		}
 	}
 
-	void CocoaDragAndDrop::coreUpdate()
+	bool CocoaDragAndDrop::_notifyDragEntered(UINT32 windowId, const Vector2I& position)
 	{
-		// First handle any queued registration/unregistration
-		{
-			Lock lock(sMutex);
-
-			for(auto& entry : sQueuedAreaOperations)
-			{
-				CocoaWindow* areaWindow;
-				entry.target->_getOwnerWindow()->getCustomAttribute("COCOA_WINDOW", &areaWindow);
+		THROW_IF_CORE_THREAD
 
-				switch(entry.type)
-				{
-					case DropAreaOpType::Register:
-						sDropAreas.push_back(DropArea(entry.target, entry.area));
-						areaWindow->_registerForDragAndDrop();
-						break;
-					case DropAreaOpType::Unregister:
-						// Remove any operations queued for this target
-						for(auto iter = sQueuedOperations.begin(); iter !=sQueuedOperations.end();)
-						{
-							if(iter->target == entry.target)
-								iter = sQueuedOperations.erase(iter);
-							else
-								++iter;
-						}
-
-						// Remove the area
-						{
-							auto iterFind = std::find_if(sDropAreas.begin(), sDropAreas.end(), [&](const DropArea& area)
-							{
-								return area.target == entry.target;
-							});
-
-							sDropAreas.erase(iterFind);
-						}
-
-						areaWindow->_unregisterForDragAndDrop();
-
-						break;
-					case DropAreaOpType::Update:
-					{
-						auto iterFind = std::find_if(sDropAreas.begin(), sDropAreas.end(), [&](const DropArea& area)
-						{
-							return area.target == entry.target;
-						});
-
-						if (iterFind != sDropAreas.end())
-							iterFind->area = entry.area;
-					}
-						break;
-				}
-			}
-
-			sQueuedAreaOperations.clear();
-		}
-	}
-
-	bool CocoaDragAndDrop::_notifyDragEntered(CocoaWindow* window, const Vector2I& position)
-	{
 		bool eventAccepted = false;
 		for(auto& entry : sDropAreas)
 		{
-			CocoaWindow* areaWindow;
-			entry.target->_getOwnerWindow()->getCustomAttribute("COCOA_WINDOW", &areaWindow);
-			if(areaWindow != window)
+			UINT32 areaWindowId = 0;
+			entry.target->_getOwnerWindow()->getCustomAttribute("WINDOW_ID", &areaWindowId);
+			if(areaWindowId != windowId)
 				continue;
 
 			if(entry.area.contains(position))
@@ -170,14 +173,16 @@ namespace bs
 		return eventAccepted;
 	}
 
-	bool CocoaDragAndDrop::_notifyDragMoved(CocoaWindow* window, const Vector2I& position)
+	bool CocoaDragAndDrop::_notifyDragMoved(UINT32 windowId, const Vector2I& position)
 	{
+		THROW_IF_CORE_THREAD
+
 		bool eventAccepted = false;
 		for(auto& entry : sDropAreas)
 		{
-			CocoaWindow* areaWindow;
-			entry.target->_getOwnerWindow()->getCustomAttribute("COCOA_WINDOW", &areaWindow);
-			if (areaWindow != window)
+			UINT32 areaWindowId = 0;
+			entry.target->_getOwnerWindow()->getCustomAttribute("WINDOW_ID", &areaWindowId);
+			if(areaWindowId != windowId)
 				continue;
 
 			if (entry.area.contains(position))
@@ -213,13 +218,15 @@ namespace bs
 		return eventAccepted;
 	}
 
-	void CocoaDragAndDrop::_notifyDragLeft(CocoaWindow* window)
+	void CocoaDragAndDrop::_notifyDragLeft(UINT32 windowId)
 	{
+		THROW_IF_CORE_THREAD
+
 		for(auto& entry : sDropAreas)
 		{
-			CocoaWindow* areaWindow;
-			entry.target->_getOwnerWindow()->getCustomAttribute("COCOA_WINDOW", &areaWindow);
-			if (areaWindow != window)
+			UINT32 areaWindowId = 0;
+			entry.target->_getOwnerWindow()->getCustomAttribute("WINDOW_ID", &areaWindowId);
+			if(areaWindowId != windowId)
 				continue;
 
 			if(entry.target->_isActive())
@@ -234,14 +241,16 @@ namespace bs
 		}
 	}
 
-	bool CocoaDragAndDrop::_notifyDragDropped(CocoaWindow* window, const Vector2I& position, const Vector<Path>& paths)
+	bool CocoaDragAndDrop::_notifyDragDropped(UINT32 windowId, const Vector2I& position, const Vector<Path>& paths)
 	{
+		THROW_IF_CORE_THREAD
+
 		bool eventAccepted = false;
 		for(auto& entry : sDropAreas)
 		{
-			CocoaWindow* areaWindow;
-			entry.target->_getOwnerWindow()->getCustomAttribute("COCOA_WINDOW", &areaWindow);
-			if(areaWindow != window)
+			UINT32 areaWindowId = 0;
+			entry.target->_getOwnerWindow()->getCustomAttribute("WINDOW_ID", &areaWindowId);
+			if(areaWindowId != windowId)
 				continue;
 
 			if(!entry.target->_isActive())

+ 4 - 11
Source/BansheeCore/Private/MacOS/BsMacOSDropTarget.h

@@ -91,13 +91,6 @@ namespace bs
 		 */
 		static void update();
 
-		/**
-		 * Transfers information about drop areas to the core thread.
-		 *
-		 * @note 	Core thread only.
-		 */
-		static void coreUpdate();
-
 		/**
 		 * Registers a new drop target. Any further events processed will take this target into account, trigger its events
 		 * and populate its data if a drop occurs.
@@ -121,16 +114,16 @@ namespace bs
 		static void unregisterDropTarget(DropTarget* target);
 
 		/** Triggered by Cocoa window when mouse cursor enters its content area while dragging. */
-		static bool _notifyDragEntered(CocoaWindow* window, const Vector2I& position);
+		static bool _notifyDragEntered(UINT32 windowId, const Vector2I& position);
 
 		/** Triggered by Cocoa window when mouse cursor moves within its content area while dragging. */
-		static bool _notifyDragMoved(CocoaWindow* window, const Vector2I& position);
+		static bool _notifyDragMoved(UINT32 windowId, const Vector2I& position);
 
 		/** Triggered by Cocoa window when mouse cursor leaves its content area while dragging.  */
-		static void _notifyDragLeft(CocoaWindow* window);
+		static void _notifyDragLeft(UINT32 windowId);
 
 		/** Triggered by Cocoa window when the user stops dragging (drops the items) within the window's content area. */
-		static bool _notifyDragDropped(CocoaWindow* window, const Vector2I& position, const Vector<Path>& paths);
+		static bool _notifyDragDropped(UINT32 windowId, const Vector2I& position, const Vector<Path>& paths);
 
 	private:
 		static Vector<DropArea> sDropAreas;

+ 3 - 0
Source/BansheeCore/Private/MacOS/BsMacOSPlatform.h

@@ -67,6 +67,9 @@ namespace bs
 		/** Sends an event notifying the system the user has scrolled the mouse wheel. */
 		static void sendMouseWheelScrollEvent(float delta);
 
+		/** Notifies the system that some window-related event has occurred. */
+		static void notifyWindowEvent(WindowEventType type, UINT32 windowId);
+
 		/** Returns the currently assigned custom cursor. */
 		static NSCursor* _getCurrentCursor();
 

+ 54 - 43
Source/BansheeCore/Private/MacOS/BsMacOSPlatform.mm

@@ -57,10 +57,10 @@
 
 namespace bs
 {
-	/** Contains information about a currently open modal window. */
+	/** Contains information about a modal window session. */
 	struct ModalWindowInfo
 	{
-		CocoaWindow* window;
+		UINT32 windowId;
 		NSModalSession session;
 	};
 
@@ -68,7 +68,7 @@ namespace bs
 	{
 		BSAppDelegate* appDelegate = nil;
 		CocoaWindow* mainWindow = nullptr;
-		Vector<CocoaWindow*> allWindows;
+		UnorderedMap<UINT32, CocoaWindow*> allWindows;
 		Vector<ModalWindowInfo> modalWindows;
 
 		BSPlatform* platformManager = nil;
@@ -85,7 +85,6 @@ namespace bs
 		WString cachedClipboardData;
 		INT32 clipboardChangeCount = -1;
 	};
-
 }
 
 /**
@@ -246,11 +245,8 @@ namespace bs
 
 	for(auto& entry : platformData->allWindows)
 	{
-		NSWindow* window = entry->_getPrivateData()->window;
-		[window
-			performSelectorOnMainThread:@selector(invalidateCursorRectsForView:)
-			withObject:[window contentView]
-			waitUntilDone:NO];
+		NSWindow* window = entry.second->_getPrivateData()->window;
+		[window invalidateCursorRectsForView:[window contentView]];
 	}
 }
 
@@ -310,6 +306,7 @@ namespace bs
 - (void)resetNonClientAreas:(NSValue*) windowValue
 {
 	bs::CocoaWindow* window = (bs::CocoaWindow*)[windowValue pointerValue];
+
 	window->_setDragZones({});
 }
 
@@ -333,10 +330,10 @@ namespace bs
 	NSDictionary* options = [NSDictionary dictionary];
 
 	NSArray* items = [pasteboard readObjectsForClasses:classes options:options];
-	if(!items)
+	if(!items || items.count == 0)
 		return nil;
 
-	return (NSString*)[items objectAtIndex:0];
+	return (NSString*) items[0];
 }}
 
 - (int32_t)getClipboardChangeCount
@@ -445,11 +442,7 @@ namespace bs
 
 	void Platform::setCursorPosition(const Vector2I& screenPos)
 	{
-		NSPoint point = NSMakePoint(screenPos.x, screenPos.y);
-		CGWarpMouseCursorPosition(point);
-
-		Lock lock(mData->cursorMutex);
-		mData->cursorPos = screenPos;
+		[mData->cursorManager setPosition:screenPos];
 	}
 
 	void Platform::captureMouse(const RenderWindow& window)
@@ -474,7 +467,7 @@ namespace bs
 		CocoaWindow* cocoaWindow;
 		window.getCustomAttribute("COCOA_WINDOW", &cocoaWindow);
 
-		int32_t requestedWindowNumber = (int32_t)cocoaWindow->_getPrivateData()->windowNumber;
+		int32_t requestedWindowNumber = (int32_t)[cocoaWindow->_getPrivateData()->window windowNumber];
 		CGPoint point = CGPointMake(screenPos.x, screenPos.y);
 
 		CFIndex numEntries = CFArrayGetCount(windowDicts);
@@ -701,17 +694,12 @@ namespace bs
 	void Platform::_update()
 	{
 		CocoaDragAndDrop::update();
-	}
 
-	void Platform::_coreUpdate()
-	{
 		{
 			Lock lock(mData->cursorMutex);
 			mData->cursorPos = [mData->cursorManager getPosition];
 		}
 
-		CocoaDragAndDrop::coreUpdate();
-
 		INT32 changeCount = [mData->platformManager getClipboardChangeCount];
 		if(mData->clipboardChangeCount != changeCount)
 		{
@@ -729,6 +717,11 @@ namespace bs
 		_messagePump();
 	}
 
+	void Platform::_coreUpdate()
+	{
+		// Do nothing
+	}
+
 	void Platform::_shutDown()
 	{
 		// Do nothing
@@ -740,7 +733,8 @@ namespace bs
 		{
 			if(!mData->modalWindows.empty())
 			{
-				if([NSApp runModalSession:mData->modalWindows.back().session] != NSModalResponseContinue)
+				NSModalSession session = mData->modalWindows.back().session;
+				if([NSApp runModalSession:session] != NSModalResponseContinue)
 					break;
 			}
 			else
@@ -765,17 +759,14 @@ namespace bs
 		if(!mData->mainWindow)
 			mData->mainWindow = window;
 
-		mData->allWindows.push_back(window);
-
 		CocoaWindow::Pimpl* windowData = window->_getPrivateData();
 		if(windowData->isModal)
 		{
-			ModalWindowInfo info;
-			info.window = window;
-			info.session = [NSApp beginModalSessionForWindow:windowData->window];
-
+			ModalWindowInfo info = { window->_getWindowId(), windowData->modalSession };
 			mData->modalWindows.push_back(info);
 		}
+
+		mData->allWindows[window->_getWindowId()] = window;
 	}
 
 	void MacOSPlatform::unregisterWindow(CocoaWindow* window)
@@ -783,22 +774,18 @@ namespace bs
 		CocoaWindow::Pimpl* windowData = window->_getPrivateData();
 		if(windowData->isModal)
 		{
-			auto findIter = std::find_if(mData->modalWindows.begin(), mData->modalWindows.begin(),
-				[window](const ModalWindowInfo& x)
-				{
-					return x.window == window;
-				});
-
-			if(findIter != mData->modalWindows.end())
-			{
-				[NSApp endModalSession:findIter->session];
-				mData->modalWindows.erase(findIter);
-			}
+			UINT32 windowId = window->_getWindowId();
+			auto iterFind = std::find_if(mData->modalWindows.begin(), mData->modalWindows.end(),
+										 [windowId](const ModalWindowInfo& x)
+										 {
+											 return x.windowId == windowId;
+										 });
+
+			if(iterFind != mData->modalWindows.end())
+				mData->modalWindows.erase(iterFind);
 		}
 
-		auto findIter = std::find(mData->allWindows.begin(), mData->allWindows.end(), window);
-		if(findIter != mData->allWindows.end())
-			mData->allWindows.erase(findIter);
+		mData->allWindows.erase(window->_getWindowId());
 
 		[mData->cursorManager unregisterWindow:windowData->window];
 
@@ -890,6 +877,30 @@ namespace bs
 		onMouseWheelScrolled(delta);
 	}
 
+	void MacOSPlatform::notifyWindowEvent(bs::WindowEventType type, bs::UINT32 windowId)
+	{
+		CocoaWindow* window = nullptr;
+		{
+			auto iterFind = mData->allWindows.find(windowId);
+			if(iterFind == mData->allWindows.end())
+				return;
+
+			window = iterFind->second;
+		}
+
+		auto renderWindow = (RenderWindow*)window->_getUserData();
+		if(renderWindow == nullptr)
+		{
+			// If it's a render window we allow the client code to handle the message, otherwise we just destroy it
+			if(type == WindowEventType::CloseRequested)
+				window->_destroy();
+
+			return;
+		}
+
+		renderWindow->_notifyWindowEvent(type);
+	}
+
 	NSCursor* MacOSPlatform::_getCurrentCursor()
 	{
 		return [mData->cursorManager currentCursor];

+ 21 - 21
Source/BansheeCore/Private/MacOS/BsMacOSWindow.h

@@ -4,6 +4,7 @@
 
 #include "Prerequisites/BsPrerequisitesUtil.h"
 #include "Math/BsVector2I.h"
+#include <Math/BsRect2I.h>
 
 #ifdef BS_COCOA_INTERNALS
 #import <Cocoa/Cocoa.h>
@@ -13,6 +14,7 @@
 @class BSWindowDelegate;
 @class BSWindowListener;
 @class BSView;
+@class BSWindow;
 #endif
 
 namespace bs
@@ -41,24 +43,26 @@ namespace bs
 		SPtr<PixelData> background;
 	};
 
-	/** Represents a Cocoa window. */
+	/**
+	 * Represents a Cocoa window. Note this class should only be used from the sim thread as Cocoa does not support
+	 * event handling, windows or views outside of the main thread.
+	 */
 	class BS_UTILITY_EXPORT CocoaWindow
 	{
 	public:
 #ifdef BS_COCOA_INTERNALS
 		struct Pimpl
 		{
-			NSWindow* window;
-			BSView* view;
-			BSWindowListener* responder;
-			BSWindowDelegate* delegate;
-
+			NSWindow* window = nil;
+			BSView* view = nil;
+			BSWindowListener* responder = nil;
+			BSWindowDelegate* delegate = nil;
+			UINT32 numDropTargets = 0;
+			bool isModal = false;
 			NSUInteger style = 0;
-			NSInteger windowNumber = 0;
-			bool isFullscreen = false;
+			bool isFullscreen;
 			NSRect windowedRect;
-			bool isModal = false;
-			UINT32 numDropTargets = 0;
+			NSModalSession modalSession = nil;
 			void* userData = nullptr;
 		};
 #else
@@ -68,13 +72,8 @@ namespace bs
 		CocoaWindow(const WINDOW_DESC& desc);
 		~CocoaWindow();
 
-		/**
-		 * Returns the current area of the window, relative to the screen.
-		 *
-		 * @param[in] topLeftOrigin		If true the coordinates will use a top-left origin coordinate system (engine native).
-		 * 								If false the coordinates will use a bottom-left origin (Cocoa native).
-		 */
-		Rect2I getArea(bool topLeftOrigin = true) const;
+		/** Returns the current area of the window, relative to the top-left origin of the screen. */
+		Rect2I getArea() const;
 
 		/** Hides the window. */
 		void hide();
@@ -116,10 +115,13 @@ namespace bs
 
 		/**
 		 * Destroys the window, cleaning up any resources and removing it from the display. No further methods should be
-		 * called on this object after it has been destroyed.
+		 * called on this object after it has been destroyed. This called automatically in the destructor.
 		 */
 		void _destroy();
 
+		/** Returns an identifier that unique identifies this window. */
+		UINT32 _getWindowId() const { return mWindowId; }
+
 		/**
 		 * Sets a portion of the window in which the user can click and drag in order to move the window. This is needed
 		 * when window has no title bar, yet you still want to allow the user to drag it by clicking on some specific area
@@ -148,9 +150,6 @@ namespace bs
 		 */
 		void _unregisterForDragAndDrop();
 
-		/** Returns the area of the screen that the window currently occupies, in Cocoa screen coordinates. */
-		Rect2I _getScreenArea() const;
-
 		/** Returns internal private data for use by friends. */
 		Pimpl* _getPrivateData() const { return m; }
 
@@ -158,6 +157,7 @@ namespace bs
 
 	private:
 		Pimpl* m;
+		UINT32 mWindowId;
 	};
 
 	/** @} */

+ 202 - 181
Source/BansheeCore/Private/MacOS/BsMacOSWindow.mm

@@ -9,6 +9,9 @@
 #include "String/BsUnicode.h"
 #include "RenderAPI/BsRenderWindow.h"
 
+using namespace bs;
+
+/** Converts a keycode reported by Cocoa into a potential input command. */
 static bool keyCodeToInputCommand(uint32_t keyCode, bool shift, bs::InputCommandType& inputCommand)
 {
 	switch(keyCode)
@@ -42,25 +45,9 @@ static bool keyCodeToInputCommand(uint32_t keyCode, bool shift, bs::InputCommand
 	return false;
 }
 
-/**
- * Overrides window so even borderless windows can become key windows (allowing resize events and cursor changes, among
- * others.
- */
-@interface BSWindow : NSWindow
-@end
-
-@implementation BSWindow
-- (BOOL)canBecomeKeyWindow
-{
-	return YES;
-}
-@end
-
 /** Implementation of NSView that handles custom cursors, transparent background images and reports the right mouse click. */
 @interface BSView : NSView
-@property (atomic, strong) NSArray* resizeAreas;
-
--(void)rightMouseDown:(NSEvent *) event;
+-(void)rightMouseDown:(NSEvent*) event;
 -(void)setBackgroundImage:(NSImage*)image;
 @end
 
@@ -127,6 +114,8 @@ static bool keyCodeToInputCommand(uint32_t keyCode, bool shift, bs::InputCommand
 }}
 @end
 
+@class BSWindow;
+
 /** Types of mouse events reported by BSWindowListener. */
 enum class MouseEventType
 {
@@ -157,26 +146,47 @@ enum class MouseEventType
 -(void) keyDown:(NSEvent *)event;
 
 // Other
--(BSWindowListener*)initWithOwner:(bs::CocoaWindow*) owner;
+-(id)initWithWindow:(BSWindow*) window;
+@end
+
+/** Listens to window move, resize, focus change and close events, handles drag and drop operations. */
+@interface BSWindowDelegate : NSObject<NSWindowDelegate, NSDraggingDestination>
+-(id)initWithWindow:(BSWindow*) window;
+@end
+
+/**
+ * Overrides window so even borderless windows can become key windows (allowing resize events and cursor changes, among
+ * others.
+ */
+@interface BSWindow : NSWindow
+@property(atomic,assign) UINT32 WindowId;
+@end
+
+@implementation BSWindow
+
+- (BOOL)canBecomeKeyWindow
+{
+	return YES;
+}
 @end
 
 @implementation BSWindowListener
 {
-	bs::CocoaWindow* mOwner;
+	BSWindow* mWindow;
 }
 @synthesize dragAreas;
 
-- (BSWindowListener* )initWithOwner:(bs::CocoaWindow*)owner
+- (id)initWithWindow:(BSWindow*) window
 {
 	self = [super init];
 
-	mOwner = owner;
+	mWindow = window;
 	dragAreas = nil;
 
 	return self;
 }
 
-- (void)handleMouseEvent:(NSEvent *)event type:(MouseEventType) type button:(bs::OSMouseButton) button
+- (void)handleMouseEvent:(NSEvent*) event type:(MouseEventType) type button:(bs::OSMouseButton) button
 {
 	NSPoint screenPos = NSEvent.mouseLocation;
 	NSUInteger modifierFlags = NSEvent.modifierFlags;
@@ -361,9 +371,7 @@ enum class MouseEventType
 
 - (void)mouseExited:(NSEvent*)event
 {
-	bs::ct::RenderWindow* renderWindow = (bs::ct::RenderWindow*)mOwner->_getUserData();
-	if(renderWindow != nullptr)
-		renderWindow->_notifyMouseLeft();
+	MacOSPlatform::notifyWindowEvent(WindowEventType::MouseLeft, mWindow.WindowId);
 }
 @end
 
@@ -385,19 +393,14 @@ NSPoint frameToContentRect(NSWindow* window, NSPoint framePoint)
 	return framePoint;
 }
 
-/** Listens to window move, resize, focus change and close events, handles drag and drop operations. */
-@interface BSWindowDelegate : NSObject<NSWindowDelegate, NSDraggingDestination>
--(id)initWithWindow:(bs::CocoaWindow*)window;
-@end
-
 @implementation BSWindowDelegate
 {
-	bs::CocoaWindow* mWindow;
+	BSWindow* mWindow;
 	NSRect mStandardZoomFrame;
 	bool mIsZooming;
 }
 
-- (id)initWithWindow:(bs::CocoaWindow*)window
+- (id)initWithWindow:(BSWindow*)window
 {
 	self = [super init];
 
@@ -408,26 +411,17 @@ NSPoint frameToContentRect(NSWindow* window, NSPoint framePoint)
 
 - (void)windowWillClose:(NSNotification *)notification
 {
-	// If it's a render window we allow the client code to handle the message
-	bs::ct::RenderWindow* renderWindow = (bs::ct::RenderWindow*)mWindow->_getUserData();
-	if(renderWindow != nullptr)
-		renderWindow->_notifyCloseRequested();
-	else // If not, we just destroy the window
-		mWindow->_destroy();
+	MacOSPlatform::notifyWindowEvent(WindowEventType::CloseRequested, mWindow.WindowId);
 }
 
 - (void)windowDidBecomeKey:(NSNotification*)notification
 {
-	bs::ct::RenderWindow* renderWindow = (bs::ct::RenderWindow*)mWindow->_getUserData();
-	if(renderWindow != nullptr)
-		renderWindow->_windowFocusReceived();
+	MacOSPlatform::notifyWindowEvent(WindowEventType::FocusReceived, mWindow.WindowId);
 }
 
 - (void)windowDidResignKey:(NSNotification*)notification
 {
-	bs::ct::RenderWindow* renderWindow = (bs::ct::RenderWindow*)mWindow->_getUserData();
-	if(renderWindow != nullptr)
-		renderWindow->_windowFocusLost();
+	MacOSPlatform::notifyWindowEvent(WindowEventType::FocusLost, mWindow.WindowId);
 }
 
 - (void)windowDidResize:(NSNotification*)notification
@@ -435,30 +429,22 @@ NSPoint frameToContentRect(NSWindow* window, NSPoint framePoint)
 	if([[notification object] isKindOfClass:[NSWindow class]])
 		bs::MacOSPlatform::_updateClipBounds([notification object]);
 
-	bs::ct::RenderWindow* renderWindow = (bs::ct::RenderWindow*)mWindow->_getUserData();
-	if(renderWindow != nullptr)
-		renderWindow->_windowMovedOrResized();
+	MacOSPlatform::notifyWindowEvent(WindowEventType::Resized, mWindow.WindowId);
 }
 
 - (void)windowDidMove:(NSNotification*)notification
 {
-	bs::ct::RenderWindow* renderWindow = (bs::ct::RenderWindow*)mWindow->_getUserData();
-	if(renderWindow != nullptr)
-		renderWindow->_windowMovedOrResized();
+	MacOSPlatform::notifyWindowEvent(WindowEventType::Moved, mWindow.WindowId);
 }
 
 - (void)windowDidMiniaturize:(NSNotification*)notification
 {
-	bs::ct::RenderWindow* renderWindow = (bs::ct::RenderWindow*)mWindow->_getUserData();
-	if(renderWindow != nullptr)
-		renderWindow->_notifyMinimized();
+	MacOSPlatform::notifyWindowEvent(WindowEventType::Minimized, mWindow.WindowId);
 }
 
 - (void)windowDidDeminiaturize:(NSNotification*)notification
 {
-	bs::ct::RenderWindow* renderWindow = (bs::ct::RenderWindow*)mWindow->_getUserData();
-	if(renderWindow != nullptr)
-		renderWindow->_notifyRestored();
+	MacOSPlatform::notifyWindowEvent(WindowEventType::Restored, mWindow.WindowId);
 }
 
 - (BOOL)windowShouldZoom:(NSWindow*)window toFrame:(NSRect)newFrame
@@ -466,17 +452,22 @@ NSPoint frameToContentRect(NSWindow* window, NSPoint framePoint)
 	// Maximizing, or restoring
 	if(mIsZooming)
 	{
-		bs::ct::RenderWindow* renderWindow = (bs::ct::RenderWindow*)mWindow->_getUserData();
-		if(renderWindow != nullptr)
-		{
-			if (newFrame.size.width == mStandardZoomFrame.size.width &&
-				newFrame.size.height == mStandardZoomFrame.size.height)
-				renderWindow->_notifyMaximized();
-			else
-				renderWindow->_notifyRestored();
-		}
+		if (newFrame.size.width == mStandardZoomFrame.size.width &&
+			newFrame.size.height == mStandardZoomFrame.size.height)
+			MacOSPlatform::notifyWindowEvent(WindowEventType::Maximized, mWindow.WindowId);
+		else
+			MacOSPlatform::notifyWindowEvent(WindowEventType::Restored, mWindow.WindowId);
 
 		mIsZooming = true;
+
+		NSRect contentRect = [mWindow contentRectForFrameRect:newFrame];
+		flipY([mWindow screen], contentRect);
+
+		Rect2I area(
+				(INT32)contentRect.origin.x,
+				(INT32)contentRect.origin.y,
+				(UINT32)contentRect.size.width,
+				(UINT32)contentRect.size.height);
 	}
 
 	return YES;
@@ -492,13 +483,11 @@ NSPoint frameToContentRect(NSWindow* window, NSPoint framePoint)
 
 - (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
 {
-	bs::CocoaWindow::Pimpl* privateData = mWindow->_getPrivateData();
-
 	NSPoint point = [sender draggingLocation];
-	point = frameToContentRect(privateData->window, point);
+	point = frameToContentRect(mWindow, point);
 
 	bs::Vector2I position((int32_t)point.x, (int32_t)point.y);
-	if(bs::CocoaDragAndDrop::_notifyDragEntered(mWindow, position))
+	if(bs::CocoaDragAndDrop::_notifyDragEntered(mWindow.WindowId, position))
 		return NSDragOperationLink;
 
 	return NSDragOperationNone;
@@ -506,13 +495,11 @@ NSPoint frameToContentRect(NSWindow* window, NSPoint framePoint)
 
 - (NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender
 {
-	bs::CocoaWindow::Pimpl* privateData = mWindow->_getPrivateData();
-
 	NSPoint point = [sender draggingLocation];
-	point = frameToContentRect(privateData->window, point);
+	point = frameToContentRect(mWindow, point);
 
 	bs::Vector2I position((int32_t)point.x, (int32_t)point.y);
-	if(bs::CocoaDragAndDrop::_notifyDragMoved(mWindow, position))
+	if(bs::CocoaDragAndDrop::_notifyDragMoved(mWindow.WindowId, position))
 		return NSDragOperationLink;
 
 	return NSDragOperationNone;
@@ -520,7 +507,7 @@ NSPoint frameToContentRect(NSWindow* window, NSPoint framePoint)
 
 - (void)draggingExited:(nullable id <NSDraggingInfo>)sender
 {
-	bs::CocoaDragAndDrop::_notifyDragLeft(mWindow);
+	bs::CocoaDragAndDrop::_notifyDragLeft(mWindow.WindowId);
 }
 
 - (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
@@ -537,14 +524,12 @@ NSPoint frameToContentRect(NSWindow* window, NSPoint framePoint)
 			paths.push_back(bs::Path(pathChars));
 		}
 
-		bs::CocoaWindow::Pimpl* privateData = mWindow->_getPrivateData();
-
 		NSPoint point = [sender draggingLocation];
-		point = frameToContentRect(privateData->window, point);
+		point = frameToContentRect(mWindow, point);
 
 		bs::Vector2I position((int32_t)point.x, (int32_t)point.y);
 
-		if(bs::CocoaDragAndDrop::_notifyDragDropped(mWindow, position, paths))
+		if(bs::CocoaDragAndDrop::_notifyDragDropped(mWindow.WindowId, position, paths))
 			return YES;
 	}
 
@@ -554,10 +539,16 @@ NSPoint frameToContentRect(NSWindow* window, NSPoint framePoint)
 
 namespace bs
 {
+	std::atomic<UINT32> gNextWindowId(1);
+
 	CocoaWindow::CocoaWindow(const WINDOW_DESC& desc)
 	{ @autoreleasepool {
 		m = bs_new<Pimpl>();
 
+		BSWindow* window = [BSWindow alloc];
+		m->isModal = desc.modal;
+		mWindowId = gNextWindowId++;
+
 		NSArray* screens = [NSScreen screens];
 
 		NSScreen* screen = nil;
@@ -569,7 +560,7 @@ namespace bs
 			NSRect screenRect = [entry frame];
 
 			if(((desc.x >= screenRect.origin.x && desc.y < (screenRect.origin.x + screenRect.size.width)) || desc.x == -1) &&
-					((desc.y >= screenRect.origin.y && desc.y < (screenRect.origin.y + screenRect.size.height)) || desc.y == -1))
+			   ((desc.y >= screenRect.origin.y && desc.y < (screenRect.origin.y + screenRect.size.height)) || desc.y == -1))
 			{
 				if(desc.x == -1)
 					x = (INT32)screenRect.origin.x + std::max(0, (INT32)screenRect.size.width - (INT32)desc.width) / 2;
@@ -594,13 +585,14 @@ namespace bs
 		if(desc.allowResize)
 			m->style |= NSWindowStyleMaskResizable;
 
-		m->window = [BSWindow alloc];
-		m->window = [m->window
-			initWithContentRect:NSMakeRect(x, y, desc.width, desc.height)
-			styleMask:(NSWindowStyleMask)m->style
-			backing:NSBackingStoreBuffered
-			defer:NO
-			screen:screen];
+		window = [window
+				initWithContentRect:NSMakeRect(x, y, desc.width, desc.height)
+				styleMask:(NSWindowStyleMask)m->style
+				backing:NSBackingStoreBuffered
+				defer:NO
+				screen:screen];
+		m->window = window;
+		window.WindowId = mWindowId;
 
 		if(desc.allowResize)
 		{
@@ -616,10 +608,10 @@ namespace bs
 		[m->window setTitle:titleString];
 		[m->window makeKeyAndOrderFront:nil];
 
-		m->responder = [[BSWindowListener alloc] initWithOwner:this];
+		m->responder = [[BSWindowListener alloc] initWithWindow:window];
 		[m->window setNextResponder:m->responder];
 
-		m->delegate = [[BSWindowDelegate alloc] initWithWindow:this];
+		m->delegate = [[BSWindowDelegate alloc] initWithWindow:window];
 		[m->window setDelegate:m->delegate];
 
 		m->view = [[BSView alloc] init];
@@ -635,8 +627,10 @@ namespace bs
 			[m->view setBackgroundImage:image];
 		}
 
-		m->isModal = desc.modal;
-		m->windowNumber = [m->window windowNumber];
+		m->isFullscreen = false;
+
+		if(desc.modal)
+			m->modalSession = [NSApp beginModalSessionForWindow:m->window];
 
 		MacOSPlatform::registerWindow(this);
 	}}
@@ -650,78 +644,130 @@ namespace bs
 	}
 
 	void CocoaWindow::move(INT32 x, INT32 y)
-	{ @autoreleasepool {
-		NSPoint point;
-		point.x = x;
-		point.y = y;
+	{
+		@autoreleasepool
+		{
+			NSPoint point;
+			point.x = x;
+			point.y = y;
 
-		[m->window setFrameTopLeftPoint:point];
-	}}
+			[m->window setFrameTopLeftPoint:point];
+		}
+	}
 
 	void CocoaWindow::resize(UINT32 width, UINT32 height)
-	{ @autoreleasepool {
-		NSRect frameRect = m->window.frame;
-		NSRect contentRect = [m->window contentRectForFrameRect:frameRect];
+	{
+		@autoreleasepool
+		{
+			NSSize size;
+			size.width = width;
+			size.height = height;
 
-		contentRect.size.width = width;
-		contentRect.size.height = height;
+			NSRect frameRect = m->window.frame;
+			NSRect contentRect = [m->window contentRectForFrameRect:frameRect];
 
-		[m->window setFrame:[m->window frameRectForContentRect:contentRect] display:YES];
-	}}
+			contentRect.size.width = size.width;
+			contentRect.size.height = size.height;
 
-	void CocoaWindow::_destroy()
-	{
-		MacOSPlatform::unregisterWindow(this);
-		m->window = nil;
+			[m->window setFrame:[m->window frameRectForContentRect:contentRect] display:YES];
+		}
 	}
 
-	Rect2I CocoaWindow::getArea(bool topLeftOrigin) const
-	{ @autoreleasepool {
-		NSRect frameRect = [m->window frame];
-		NSRect contentRect = [m->window contentRectForFrameRect:frameRect];
+	Rect2I CocoaWindow::getArea() const
+	{
+		@autoreleasepool
+		{
+			NSRect frameRect = [m->window frame];
+			NSRect contentRect = [m->window contentRectForFrameRect:frameRect];
 
-		if(topLeftOrigin)
 			flipY([m->window screen], contentRect);
 
-		return Rect2I(
-			(INT32)contentRect.origin.x,
-			(INT32)contentRect.origin.y,
-			(UINT32)contentRect.size.width,
-			(UINT32)contentRect.size.height
-		);
-	}}
+			return Rect2I(
+					(INT32)contentRect.origin.x,
+					(INT32)contentRect.origin.y,
+					(UINT32)contentRect.size.width,
+					(UINT32)contentRect.size.height);
+		}
+	}
 
 	void CocoaWindow::hide()
-	{ @autoreleasepool {
-		[m->window orderOut:nil];
-	}}
+	{
+		@autoreleasepool
+		{
+			[m->window orderOut:nil];
+		}
+	}
 
 	void CocoaWindow::show()
-	{ @autoreleasepool {
-		[m->window makeKeyAndOrderFront:nil];
-	}}
+	{
+		@autoreleasepool
+		{
+			[m->window makeKeyAndOrderFront:nil];
+		}
+	}
 
 	void CocoaWindow::maximize()
-	{ @autoreleasepool {
-		if(![m->window isZoomed])
-			[m->window zoom:nil];
-	}}
+	{
+		@autoreleasepool
+		{
+			if(![m->window isZoomed])
+				[m->window zoom:nil];
+		}
+	}
 
 	void CocoaWindow::minimize()
-	{ @autoreleasepool {
-		[m->window miniaturize:nil];
-	}}
+	{
+		@autoreleasepool
+		{
+			[m->window miniaturize:nil];
+		}
+	}
 
 	void CocoaWindow::restore()
-	{ @autoreleasepool {
-		if([m->window isMiniaturized])
-			[m->window deminiaturize:nil];
-		else if([m->window isZoomed])
-			[m->window zoom:nil];
-	}}
+	{
+		@autoreleasepool
+		{
+			if([m->window isMiniaturized])
+				[m->window deminiaturize:nil];
+			else if([m->window isZoomed])
+				[m->window zoom:nil];
+		}
+	}
+
+	void CocoaWindow::setWindowed()
+	{
+		@autoreleasepool
+		{
+			if(m->isFullscreen)
+			{
+				[m->window setStyleMask:(NSWindowStyleMask)m->style];
+				[m->window setFrame:m->windowedRect display:NO];
+				[m->window setLevel:NSNormalWindowLevel];
+
+				m->isFullscreen = false;
+			}
+		}
+	}
+
+	void CocoaWindow::setFullscreen()
+	{
+		@autoreleasepool
+		{
+			if(!m->isFullscreen)
+				m->windowedRect = [m->window frame];
+
+			NSRect frame = [[m->window screen] frame];
+			[m->window setStyleMask:NSWindowStyleMaskBorderless];
+			[m->window setFrame:frame display:NO];
+			[m->window setLevel:NSMainMenuWindowLevel+1];
+			[m->window makeKeyAndOrderFront:nil];
+
+			m->isFullscreen = true;
+		}
+	}
 
 	Vector2I CocoaWindow::windowToScreenPos(const Vector2I& windowPos) const
-	{ @autoreleasepool {
+	{
 		NSRect frameRect = [m->window frame];
 		NSRect contentRect = [m->window contentRectForFrameRect:frameRect];
 
@@ -732,10 +778,10 @@ namespace bs
 		screenPos.y = windowPos.y + (INT32)contentRect.origin.y;
 
 		return screenPos;
-	}}
+	}
 
 	Vector2I CocoaWindow::screenToWindowPos(const Vector2I& screenPos) const
-	{ @autoreleasepool {
+	{
 		NSRect frameRect = [m->window frame];
 		NSRect contentRect = [m->window contentRectForFrameRect:frameRect];
 
@@ -746,43 +792,31 @@ namespace bs
 		windowPos.y = screenPos.y - (INT32) contentRect.origin.y;
 
 		return windowPos;
-	}}
-
-	void CocoaWindow::setWindowed()
-	{
-		if(m->isFullscreen)
-		{
-			[m->window setStyleMask:(NSWindowStyleMask)m->style];
-			[m->window setFrame:m->windowedRect display:NO];
-			[m->window setLevel:NSNormalWindowLevel];
-
-			m->isFullscreen = false;
-		}
 	}
 
-	void CocoaWindow::setFullscreen()
+	void CocoaWindow::_destroy()
 	{
-		if(!m->isFullscreen)
-			m->windowedRect = [m->window frame];
+		if(m->isModal)
+			[NSApp endModalSession:m->modalSession];
 
-		NSRect frame = [[m->window screen] frame];
-		[m->window setStyleMask:NSWindowStyleMaskBorderless];
-		[m->window setFrame:frame display:NO];
-		[m->window setLevel:NSMainMenuWindowLevel+1];
-		[m->window makeKeyAndOrderFront:nil];
+		// TODO - Need to unregister modal window as well
+		MacOSPlatform::unregisterWindow(this);
 
-		m->isFullscreen = true;
+		m->window = nil;
 	}
 
 	void CocoaWindow::_setDragZones(const Vector<Rect2I>& rects)
-	{ @autoreleasepool {
-		NSMutableArray* array = [[NSMutableArray alloc] init];
+	{
+		@autoreleasepool
+		{
+			NSMutableArray* array = [[NSMutableArray alloc] init];
 
-		for(auto& entry : rects)
-			[array addObject:[NSValue valueWithBytes:&entry objCType:@encode(Rect2I)]];
+			for(auto& entry : rects)
+				[array addObject:[NSValue valueWithBytes:&entry objCType:@encode(Rect2I)]];
 
-		[m->responder setDragAreas:array];
-	}}
+			[m->responder setDragAreas:array];
+		}
+	}
 
 	void CocoaWindow::_setUserData(void* data)
 	{
@@ -810,17 +844,4 @@ namespace bs
 		if(m->numDropTargets == 0)
 			[m->window unregisterDraggedTypes];
 	}
-
-	Rect2I CocoaWindow::_getScreenArea() const
-	{
-		NSRect screenRect = [[m->window screen] frame];
-
-		Rect2I area;
-		area.x = (INT32)screenRect.origin.x;
-		area.y = (INT32)screenRect.origin.y;
-		area.width = (UINT32)screenRect.size.width;
-		area.height = (UINT32)screenRect.size.height;
-
-		return area;
-	}
 }

+ 197 - 98
Source/BansheeCore/RenderAPI/BsRenderWindow.cpp

@@ -231,6 +231,109 @@ namespace bs
 		return static_cast<const RenderWindowProperties&>(getPropertiesInternal());
 	}
 
+	void RenderWindow::_notifyWindowEvent(WindowEventType type)
+	{
+		THROW_IF_CORE_THREAD;
+
+		ct::RenderWindow* coreWindow = getCore().get();
+		RenderWindowProperties& syncProps = coreWindow->getSyncedProperties();
+		RenderWindowProperties& props = const_cast<RenderWindowProperties&>(getProperties());
+
+		switch(type)
+		{
+			case WindowEventType::Resized:
+			{
+				{
+					ScopedSpinLock lock(coreWindow->mLock);
+					syncProps.width = props.width;
+					syncProps.height = props.height;
+				}
+
+				bs::RenderWindowManager::instance().notifySyncDataDirty(coreWindow);
+				bs::RenderWindowManager::instance().notifyMovedOrResized(coreWindow);
+				_windowMovedOrResized();
+
+				break;
+			}
+			case WindowEventType::Moved:
+			{
+				{
+					ScopedSpinLock lock(coreWindow->mLock);
+					syncProps.top = props.top;
+					syncProps.left = props.left;
+				}
+
+				bs::RenderWindowManager::instance().notifySyncDataDirty(coreWindow);
+				bs::RenderWindowManager::instance().notifyMovedOrResized(coreWindow);
+				_windowMovedOrResized();
+
+				break;
+			}
+			case WindowEventType::FocusReceived:
+			{
+				{
+					ScopedSpinLock lock(coreWindow->mLock);
+					syncProps.hasFocus = true;
+				}
+
+				bs::RenderWindowManager::instance().notifySyncDataDirty(coreWindow);
+				bs::RenderWindowManager::instance().notifyFocusReceived(coreWindow);
+				break;
+			}
+			case WindowEventType::FocusLost:
+			{
+				{
+					ScopedSpinLock lock(coreWindow->mLock);
+					syncProps.hasFocus = false;
+				}
+
+				bs::RenderWindowManager::instance().notifySyncDataDirty(coreWindow);
+				bs::RenderWindowManager::instance().notifyFocusLost(coreWindow);
+				break;
+			}
+			case WindowEventType::Minimized:
+			{
+				{
+					ScopedSpinLock lock(coreWindow->mLock);
+					syncProps.isMaximized = false;
+				}
+
+				bs::RenderWindowManager::instance().notifySyncDataDirty(coreWindow);
+				break;
+			}
+			case WindowEventType::Maximized:
+			{
+				{
+					ScopedSpinLock lock(coreWindow->mLock);
+					syncProps.isMaximized = true;
+				}
+
+				bs::RenderWindowManager::instance().notifySyncDataDirty(coreWindow);
+				break;
+			}
+			case WindowEventType::Restored:
+			{
+				{
+					ScopedSpinLock lock(coreWindow->mLock);
+					syncProps.isMaximized = false;
+				}
+
+				bs::RenderWindowManager::instance().notifySyncDataDirty(coreWindow);
+				break;
+			}
+			case WindowEventType::MouseLeft:
+			{
+				bs::RenderWindowManager::instance().notifyMouseLeft(coreWindow);
+				break;
+			}
+			case WindowEventType::CloseRequested:
+			{
+				bs::RenderWindowManager::instance().notifyCloseRequested(coreWindow);
+				break;
+			}
+		}
+	}
+
 	namespace ct
 	{
 	RenderWindow::RenderWindow(const RENDER_WINDOW_DESC& desc, UINT32 windowId)
@@ -264,110 +367,106 @@ namespace bs
 		THROW_IF_NOT_CORE_THREAD;
 	}
 
-	void RenderWindow::_windowMovedOrResized()
+	void RenderWindow::_notifyWindowEvent(WindowEventType type)
 	{
-		THROW_IF_NOT_CORE_THREAD;
+		THROW_IF_CORE_THREAD;
 
+		RenderWindowProperties& syncProps = getSyncedProperties();
 		RenderWindowProperties& props = const_cast<RenderWindowProperties&>(getProperties());
-		{
-			ScopedSpinLock lock(mLock);
-			getSyncedProperties().top = props.top;
-			getSyncedProperties().left = props.left;
-			getSyncedProperties().width = props.width;
-			getSyncedProperties().height = props.height;
-		}
-
-		bs::RenderWindowManager::instance().notifySyncDataDirty(this);
-		bs::RenderWindowManager::instance().notifyMovedOrResized(this);
-	}
 
-	void RenderWindow::_windowFocusReceived()
-	{
-		THROW_IF_NOT_CORE_THREAD;
-
-		RenderWindowProperties& properties = const_cast<RenderWindowProperties&>(getProperties());
-		properties.hasFocus = true;
+		switch(type)
 		{
-			ScopedSpinLock lock(mLock);
-			getSyncedProperties().hasFocus = true;
+			case WindowEventType::Resized:
+			{
+				{
+					ScopedSpinLock lock(mLock);
+					syncProps.width = props.width;
+					syncProps.height = props.height;
+				}
+
+				bs::RenderWindowManager::instance().notifySyncDataDirty(this);
+				bs::RenderWindowManager::instance().notifyMovedOrResized(this);
+				_windowMovedOrResized();
+
+				break;
+			}
+			case WindowEventType::Moved:
+			{
+				{
+					ScopedSpinLock lock(mLock);
+					syncProps.top = props.top;
+					syncProps.left = props.left;
+				}
+
+				bs::RenderWindowManager::instance().notifySyncDataDirty(this);
+				bs::RenderWindowManager::instance().notifyMovedOrResized(this);
+				_windowMovedOrResized();
+
+				break;
+			}
+			case WindowEventType::FocusReceived:
+			{
+				{
+					ScopedSpinLock lock(mLock);
+					syncProps.hasFocus = true;
+				}
+
+				bs::RenderWindowManager::instance().notifySyncDataDirty(this);
+				bs::RenderWindowManager::instance().notifyFocusReceived(this);
+				break;
+			}
+			case WindowEventType::FocusLost:
+			{
+				{
+					ScopedSpinLock lock(mLock);
+					syncProps.hasFocus = false;
+				}
+
+				bs::RenderWindowManager::instance().notifySyncDataDirty(this);
+				bs::RenderWindowManager::instance().notifyFocusLost(this);
+				break;
+			}
+			case WindowEventType::Minimized:
+			{
+				{
+					ScopedSpinLock lock(mLock);
+					syncProps.isMaximized = false;
+				}
+
+				bs::RenderWindowManager::instance().notifySyncDataDirty(this);
+				break;
+			}
+			case WindowEventType::Maximized:
+			{
+				{
+					ScopedSpinLock lock(mLock);
+					syncProps.isMaximized = true;
+				}
+
+				bs::RenderWindowManager::instance().notifySyncDataDirty(this);
+				break;
+			}
+			case WindowEventType::Restored:
+			{
+				{
+					ScopedSpinLock lock(mLock);
+					syncProps.isMaximized = false;
+				}
+
+				bs::RenderWindowManager::instance().notifySyncDataDirty(this);
+				break;
+			}
+			case WindowEventType::MouseLeft:
+			{
+				bs::RenderWindowManager::instance().notifyMouseLeft(this);
+				break;
+			}
+			case WindowEventType::CloseRequested:
+			{
+				bs::RenderWindowManager::instance().notifyCloseRequested(this);
+				break;
+			}
 		}
-
-		bs::RenderWindowManager::instance().notifySyncDataDirty(this);
-		bs::RenderWindowManager::instance().notifyFocusReceived(this);
-	}
-
-	void RenderWindow::_windowFocusLost()
-	{
-		THROW_IF_NOT_CORE_THREAD;
-
-		RenderWindowProperties& properties = const_cast<RenderWindowProperties&>(getProperties());
-		properties.hasFocus = false;
-		{
-			ScopedSpinLock lock(mLock);
-			getSyncedProperties().hasFocus = false;
-		}
-
-		bs::RenderWindowManager::instance().notifySyncDataDirty(this);
-		bs::RenderWindowManager::instance().notifyFocusLost(this);
-	}
-
-	void RenderWindow::_notifyMaximized()
-	{
-		THROW_IF_NOT_CORE_THREAD;
-
-		RenderWindowProperties& props = const_cast<RenderWindowProperties&>(getProperties());
-
-		props.isMaximized = true;
-		{
-			ScopedSpinLock lock(mLock);
-			getSyncedProperties().isMaximized = true;
-		}
-
-		bs::RenderWindowManager::instance().notifySyncDataDirty(this);
-	}
-
-	void RenderWindow::_notifyMinimized()
-	{
-		THROW_IF_NOT_CORE_THREAD;
-
-		RenderWindowProperties& props = const_cast<RenderWindowProperties&>(getProperties());
-
-		props.isMaximized = false;
-		{
-			ScopedSpinLock lock(mLock);
-			getSyncedProperties().isMaximized = false;
-		}
-
-		bs::RenderWindowManager::instance().notifySyncDataDirty(this);
-	}
-
-	void RenderWindow::_notifyRestored()
-	{
-		THROW_IF_NOT_CORE_THREAD;
-
-		RenderWindowProperties& props = const_cast<RenderWindowProperties&>(getProperties());
-
-		props.isMaximized = false;
-		{
-			ScopedSpinLock lock(mLock);
-			getSyncedProperties().isMaximized = false;
-		}
-
-		bs::RenderWindowManager::instance().notifySyncDataDirty(this);
-	}
-
-	void RenderWindow::_notifyMouseLeft()
-	{
-		THROW_IF_NOT_CORE_THREAD;
-
-		bs::RenderWindowManager::instance().notifyMouseLeft(this);
-	}
-
-	void RenderWindow::_notifyCloseRequested()
-	{
-		THROW_IF_NOT_CORE_THREAD;
-
-		bs::RenderWindowManager::instance().notifyCloseRequested(this);
 	}
 
 	const RenderWindowProperties& RenderWindow::getProperties() const

+ 55 - 64
Source/BansheeCore/RenderAPI/BsRenderWindow.h

@@ -11,6 +11,35 @@ namespace bs
 {
 	class RenderWindowManager;
 
+	/** @addtogroup RenderAPI-Internal
+	 *  @{
+	 */
+
+	/** Types of events that a RenderWindow can be notified of. */
+	enum class WindowEventType
+	{
+		/** Triggered when window size changes. */
+		Resized,
+		/** Triggered when window position changes. */
+		Moved,
+		/** Triggered when window receives input focus. */
+		FocusReceived,
+		/** Triggered when window loses input focus. */
+		FocusLost,
+		/** Triggered when the window is minimized (iconified). */
+		Minimized,
+		/** Triggered when the window is expanded to cover the current screen. */
+		Maximized,
+		/** Triggered when the window leaves minimized or maximized state. */
+		Restored,
+		/** Triggered when the mouse pointer leaves the window area. */
+		MouseLeft,
+		/** Triggered when the user wants to close the window. */
+		CloseRequested,
+	};
+
+	/** @} */
+
 	/** @addtogroup RenderAPI
 	 *  @{
 	 */
@@ -97,7 +126,7 @@ namespace bs
 		 * @param[in]	width		Width of the window in pixels.
 		 * @param[in]	height		Height of the window in pixels.
 		 */
-		void resize(UINT32 width, UINT32 height);
+		virtual void resize(UINT32 width, UINT32 height);
 
 		/**	
 		 * Move the window to specified screen coordinates. 
@@ -107,63 +136,63 @@ namespace bs
 		 * 
 		 * @note This is an @ref asyncMethod "asynchronous method".
 		 */
-		void move(INT32 left, INT32 top);
+		virtual void move(INT32 left, INT32 top);
 
 		/** 
 		 * Hides the window. 
 		 * 
 		 * @note This is an @ref asyncMethod "asynchronous method".
 		 */
-		void hide();
+		virtual void hide();
 
 		/** 
 		 * Shows a previously hidden window. 
 		 * 
 		 * @note This is an @ref asyncMethod "asynchronous method".
 		 */
-		void show();
+		virtual void show();
 
 		/** 
 		 * @copydoc ct::RenderWindow::minimize  
 		 * 
 		 * @note This is an @ref asyncMethod "asynchronous method".
 		 */
-		void minimize();
+		virtual void minimize();
 
 		/** 
 		 * @copydoc ct::RenderWindow::maximize 
 		 * 
 		 * @note This is an @ref asyncMethod "asynchronous method".
 		 */
-		void maximize();
+		virtual void maximize();
 
 		/** 
 		 * @copydoc ct::RenderWindow::restore  
 		 * 
 		 * @note This is an @ref asyncMethod "asynchronous method".
 		 */
-		void restore();
+		virtual void restore();
 
 		/** 
 		 * @copydoc ct::RenderWindow::setFullscreen(UINT32, UINT32, float, UINT32) 
 		 * 
 		 * @note This is an @ref asyncMethod "asynchronous method".
 		 */
-		void setFullscreen(UINT32 width, UINT32 height, float refreshRate = 60.0f, UINT32 monitorIdx = 0);
+		virtual void setFullscreen(UINT32 width, UINT32 height, float refreshRate = 60.0f, UINT32 monitorIdx = 0);
 
 		/** 
 		 * @copydoc ct::RenderWindow::setFullscreen(const VideoMode&) 
 		 * 
 		 * @note This is an @ref asyncMethod "asynchronous method".
 		 */
-		void setFullscreen(const VideoMode& videoMode);
+		virtual void setFullscreen(const VideoMode& videoMode);
 
 		/** 
 		 * @copydoc ct::RenderWindow::setWindowed 
 		 * 
 		 * @note This is an @ref asyncMethod "asynchronous method".
 		 */
-		void setWindowed(UINT32 width, UINT32 height);
+		virtual void setWindowed(UINT32 width, UINT32 height);
 
 		/**	Retrieves a core implementation of a render window usable only from the core thread. */
 		SPtr<ct::RenderWindow> getCore() const;
@@ -183,6 +212,18 @@ namespace bs
 		/** Triggers when the OS requests that the window is closed (e.g. user clicks on the X button in the title bar). */
 		Event<void()> onCloseRequested;
 
+		/**
+		 * @name Internal
+		 */
+
+		/** Notifies the window that a specific event occurred. Usually called by the platform specific main event loop. */
+		void _notifyWindowEvent(WindowEventType type);
+
+		/** Method that triggers whenever the window changes size or position. */
+		virtual void _windowMovedOrResized() { }
+
+		/** @} */
+
 	protected:
 		friend class RenderWindowManager;
 
@@ -282,61 +323,11 @@ namespace bs
 		/**	Returns properties that describe the render window. */
 		const RenderWindowProperties& getProperties() const;
 
-		/**
-		 * Called when window is moved or resized.
-		 *
-		 * @note	Core thread.
-		 */
-		virtual void _windowMovedOrResized();
+		/** Notifies the window that a specific event occurred. Usually called by the platform specific main event loop. */
+		void _notifyWindowEvent(WindowEventType type);
 
-		/**
-		 * Called when window has received focus.
-		 *
-		 * @note	Core thread.
-		 */
-		virtual void _windowFocusReceived();
-
-		/**
-		 * Called when window has lost focus.
-		 *
-		 * @note	Core thread.
-		 */
-		virtual void _windowFocusLost();
-
-		/**
-		 * Called when window has been maximized.
-		 *
-		 * @note	Core thread.
-		 */
-		virtual void _notifyMaximized();
-
-		/**
-		 * Called when window has been minimized.
-		 *
-		 * @note	Core thread.
-		 */
-		virtual void _notifyMinimized();
-
-		/**
-		 * Called when window has been restored from minimized or maximized state.
-		 *
-		 * @note	Core thread.
-		 */
-		virtual void _notifyRestored();
-
-		/**
-		 * Called when the mouse leaves the window.
-		 *
-		 * @note	Core thread.
-		 */
-		virtual void _notifyMouseLeft();
-
-		/**
-		 * Called when the users requests for the window to be closed.
-		 *
-		 * @note	Core thread.
-		 */
-		virtual void _notifyCloseRequested();
+		/** Method that triggers whenever the window changes size or position. */
+		virtual void _windowMovedOrResized() { }
 	protected:
 		friend class bs::RenderWindow;
 		friend class RenderWindowManager;

+ 2 - 2
Source/BansheeEngine/Platform/BsSplashScreen.cpp

@@ -175,12 +175,12 @@ namespace bs
 
 	void SplashScreen::show()
 	{
-		gCoreThread().queueCommand(&SplashScreen::create, CTQF_InternalQueue);
+		SplashScreen::create();
 	}
 
 	void SplashScreen::hide()
 	{
-		gCoreThread().queueCommand(&SplashScreen::destroy, CTQF_InternalQueue);
+		SplashScreen::destroy();
 	}
 
 	void SplashScreen::create()

+ 5 - 1
Source/BansheeGLRenderAPI/BsGLPixelBuffer.cpp

@@ -449,7 +449,11 @@ namespace bs { namespace ct
 				glFramebufferTexture3D(GL_FRAMEBUFFER, attachment, mFaceTarget, mTextureID, mLevel, zoffset);
 				BS_CHECK_GL_ERROR();
 				break;
-			default: // Texture arrays and cube maps
+			case GL_TEXTURE_CUBE_MAP:
+				glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, mFaceTarget, mTextureID, mLevel);
+				BS_CHECK_GL_ERROR();
+				break;
+			default: // Texture arrays
 				glFramebufferTextureLayer(GL_FRAMEBUFFER, attachment, mTextureID, mLevel, mFace);
 				BS_CHECK_GL_ERROR();
 				break;

+ 8 - 0
Source/BansheeGLRenderAPI/GLSL/BsGLSLGpuProgram.cpp

@@ -249,6 +249,14 @@ namespace bs { namespace ct
 
 			mCompileError = "";
 			mIsCompiled = !checkForGLSLError(mGLHandle, mCompileError);
+
+
+
+			// DEBUG ONLY
+			if(!mIsCompiled)
+			{
+				LOGWRN(mCompileError);
+			}
 		}
 
 		if (mIsCompiled)

+ 47 - 43
Source/BansheeGLRenderAPI/MacOS/BsMacOSRenderWindow.h

@@ -39,9 +39,42 @@ namespace bs
 		/** @copydoc RenderWindow::windowToScreenPos */
 		Vector2I windowToScreenPos(const Vector2I& windowPos) const override;
 
+		/** @copydoc RenderWindow::resize */
+		void resize(UINT32 width, UINT32 height) override;
+
+		/** @copydoc RenderWindow::move */
+		void move(INT32 left, INT32 top) override;
+
+		/** @copydoc RenderWindow::hide */
+		void hide() override;
+
+		/** @copydoc RenderWindow::show */
+		void show() override;
+
+		/** @copydoc RenderWindow::minimize */
+		void minimize() override;
+
+		/** @copydoc RenderWindow::maximize */
+		void maximize() override;
+
+		/** @copydoc RenderWindow::restore */
+		void restore() override;
+
+		/** @copydoc RenderWindow::setFullscreen(UINT32, UINT32, float, UINT32) */
+		void setFullscreen(UINT32 width, UINT32 height, float refreshRate = 60.0f, UINT32 monitorIdx = 0) override;
+
+		/** @copydoc RenderWindow::setFullscreen(const VideoMode&) */
+		void setFullscreen(const VideoMode& videoMode) override;
+
+		/** @copydoc RenderWindow::setWindowed */
+		void setWindowed(UINT32 width, UINT32 height) override;
+
 		/** @copydoc RenderWindow::getCore */
 		SPtr<ct::MacOSRenderWindow> getCore() const;
 
+		/** Called when window is moved or resized. */
+		void _windowMovedOrResized() override;
+
 	protected:
 		friend class GLRenderWindowManager;
 		friend class ct::MacOSGLSupport;
@@ -49,15 +82,27 @@ namespace bs
 
 		MacOSRenderWindow(const RENDER_WINDOW_DESC& desc, UINT32 windowId, ct::MacOSGLSupport& glSupport);
 
+		/** Changes the display mode (resolution, refresh rate) of the specified output device. */
+		void setDisplayMode(const VideoOutputInfo& output, const VideoMode& mode);
+
 		/** @copydoc RenderWindow::getProperties */
 		const RenderTargetProperties& getPropertiesInternal() const override { return mProperties; }
 
 		/** @copydoc RenderWindow::syncProperties */
 		void syncProperties() override;
 
+		/** @copydoc CoreObject::initialize() */
+		void initialize() override;
+
+		/** @copydoc CoreObject::destroy() */
+		void destroy() override;
+
 	private:
+		CocoaWindow* mWindow = nullptr;
+		bool mIsChild = false;
+
 		RenderWindowProperties mProperties;
-		const ct::MacOSGLSupport& mGLSupport;
+		ct::MacOSGLSupport& mGLSupport;
 	};
 
 	namespace ct
@@ -71,28 +116,6 @@ namespace bs
 		{
 		public:
 			MacOSRenderWindow(const RENDER_WINDOW_DESC& desc, UINT32 windowId, MacOSGLSupport& glSupport);
-			~MacOSRenderWindow();
-
-			/** @copydoc RenderWindow::setFullscreen(UINT32, UINT32, float, UINT32) */
-			void setFullscreen(UINT32 width, UINT32 height, float refreshRate = 60.0f, UINT32 monitorIdx = 0) override;
-
-			/** @copydoc RenderWindow::setFullscreen(const VideoMode&) */
-			void setFullscreen(const VideoMode& videoMode) override;
-
-			/** @copydoc RenderWindow::setWindowed */
-			void setWindowed(UINT32 width, UINT32 height) override;
-
-			/** @copydoc RenderWindow::setHidden */
-			void setHidden(bool hidden) override;
-
-			/** @copydoc RenderWindow::minimize */
-			void minimize() override;
-
-			/** @copydoc RenderWindow::maximize */
-			void maximize() override;
-
-			/** @copydoc RenderWindow::restore */
-			void restore() override;
 
 			/** @copydoc RenderWindow::move */
 			void move(INT32 left, INT32 top) override;
@@ -108,7 +131,7 @@ namespace bs
 			 *
 			 * @param[out]	dst		Previously allocated buffer to read the contents into. Must be of valid size.
 			 * @param[in]	buffer	Frame buffer to read the contents from.
-			 */
+			 *
 			void copyToMemory(PixelData& dst, FrameBuffer buffer);
 
 			/** @copydoc RenderWindow::swapBuffers */
@@ -117,21 +140,12 @@ namespace bs
 			/** @copydoc RenderWindow::getCustomAttribute */
 			void getCustomAttribute(const String& name, void* pData) const override;
 
-			/** @copydoc RenderWindow::setActive */
-			void setActive(bool state) override;
-
-			/** @copydoc RenderWindow::_windowMovedOrResized */
-			void _windowMovedOrResized() override;
-
 			/** Returns a lock that can be used for accessing synced properties. */
 			SpinLock& _getPropertiesLock() { return mLock;}
 
 		protected:
 			friend class MacOSGLSupport;
 
-			/** @copydoc CoreObject::initialize */
-			void initialize() override;
-
 			/** @copydoc RenderWindow::getProperties */
 			const RenderTargetProperties& getPropertiesInternal() const override { return mProperties; }
 
@@ -141,24 +155,14 @@ namespace bs
 			/** @copydoc RenderWindow::syncProperties */
 			void syncProperties() override;
 
-			/** Changes the display mode (resolution, refresh rate) of the specified output device. */
-			void setDisplayMode(const VideoOutputInfo& output, const VideoMode& mode);
-
 		protected:
 			friend class bs::MacOSRenderWindow;
 
-			CocoaWindow* mWindow;
 			SPtr<MacOSContext> mContext;
 			ct::MacOSGLSupport& mGLSupport;
 			RenderWindowProperties mProperties;
 			RenderWindowProperties mSyncedProperties;
-			bool mIsChild;
 			bool mShowOnSwap;
-
-			// Coordinate conversions
-			Mutex mDimensionsMutex;
-			Rect2I mScreenArea;
-			Rect2I mNativeWindowArea;
 		};
 	}
 

+ 313 - 300
Source/BansheeGLRenderAPI/MacOS/BsMacOSRenderWindow.mm

@@ -17,355 +17,414 @@ namespace bs
 			:RenderWindow(desc, windowId), mProperties(desc), mGLSupport(glSupport)
 	{ }
 
-	void MacOSRenderWindow::getCustomAttribute(const String& name, void* data) const
+	void MacOSRenderWindow::initialize()
 	{
-		if(name == "WINDOW" || name == "COCOA_WINDOW")
-		{
-			blockUntilCoreInitialized();
-			getCore()->getCustomAttribute(name, data);
-			return;
-		}
-	}
+		RenderWindowProperties& props = mProperties;
 
-	Vector2I MacOSRenderWindow::screenToWindowPos(const Vector2I& screenPos) const
-	{
-		blockUntilCoreInitialized();
+		props.isFullScreen = mDesc.fullscreen;
+		mIsChild = false;
 
-		Vector2I point;
-		point.x = screenPos.x - mProperties.left;
-		point.y = screenPos.y - mProperties.top;
+		WINDOW_DESC windowDesc;
+		windowDesc.x = mDesc.left;
+		windowDesc.y = mDesc.top;
+		windowDesc.width = mDesc.videoMode.getWidth();
+		windowDesc.height = mDesc.videoMode.getHeight();
+		windowDesc.title = mDesc.title;
+		windowDesc.showDecorations = mDesc.showTitleBar;
+		windowDesc.allowResize = mDesc.allowResize;
+		windowDesc.modal = mDesc.modal;
 
-		return point;
-	}
+		auto iter = mDesc.platformSpecific.find("parentWindowHandle");
+		mIsChild = iter != mDesc.platformSpecific.end();
 
-	Vector2I MacOSRenderWindow::windowToScreenPos(const Vector2I& windowPos) const
-	{
-		blockUntilCoreInitialized();
+		props.isFullScreen = mDesc.fullscreen && !mIsChild;
 
-		Vector2I point;
-		point.x = windowPos.x + mProperties.left;
-		point.y = windowPos.y + mProperties.top;
+		mShowOnSwap = mDesc.hideUntilSwap;
+		props.isHidden = mDesc.hideUntilSwap || mDesc.hidden;
 
-		return point;
-	}
+		mWindow = bs_new<CocoaWindow>(windowDesc);
+		mWindow->_setUserData(this);
 
-	SPtr<ct::MacOSRenderWindow> MacOSRenderWindow::getCore() const
-	{
-		return std::static_pointer_cast<ct::MacOSRenderWindow>(mCoreSpecific);
-	}
+		Rect2I area = mWindow->getArea();
+		props.width = area.width;
+		props.height = area.height;
+		props.top = area.y;
+		props.left = area.x;
 
-	void MacOSRenderWindow::syncProperties()
-	{
-		ScopedSpinLock lock(getCore()->_getPropertiesLock());
-		mProperties = getCore()->mSyncedProperties;
+		props.hwGamma = mDesc.gamma;
+		props.multisampleCount = mDesc.multisampleCount;
+
+		mContext = mGLSupport.createContext(mDesc.depthBuffer, mDesc.multisampleCount);
+
+		if(mDesc.fullscreen && !mIsChild)
+			setFullscreen(mDesc.videoMode);
+
+		if(mDesc.vsync && mDesc.vsyncInterval > 0)
+			setVSync(true, mDesc.vsyncInterval);
+
+		RenderWindow::initialize();
+
+		{
+			ScopedSpinLock lock(getCore()->mLock);
+			getCore()->mSyncedProperties = props;
+		}
+
+		bs::RenderWindowManager::instance().notifySyncDataDirty(getCore().get());
 	}
 
-	namespace ct
+	void MacOSRenderWindow::destroy()
 	{
-		MacOSRenderWindow::MacOSRenderWindow(const RENDER_WINDOW_DESC& desc, UINT32 windowId, MacOSGLSupport& glsupport)
-			: RenderWindow(desc, windowId), mWindow(nullptr), mContext(nullptr), mGLSupport(glsupport), mProperties(desc)
-			, mSyncedProperties(desc), mIsChild(false), mShowOnSwap(false)
-		{ }
+		// Make sure to set the original desktop video mode before we exit
+		if(mProperties.isFullScreen)
+			setWindowed(50, 50);
 
-		MacOSRenderWindow::~MacOSRenderWindow()
+		if (mWindow != nullptr)
 		{
-			// Make sure to set the original desktop video mode before we exit
-			if(mProperties.isFullScreen)
-				setWindowed(50, 50);
-
-			if (mWindow != nullptr)
-			{
-				bs_delete(mWindow);
-				mWindow = nullptr;
-			}
+			bs_delete(mWindow);
+			mWindow = nullptr;
 		}
+	}
 
-		void MacOSRenderWindow::initialize()
+	void MacOSRenderWindow::resize(UINT32 width, UINT32 height)
+	{
+		RenderWindowProperties& props = mProperties;
+		if (!props.isFullScreen)
 		{
-			RenderWindowProperties& props = mProperties;
-
-			props.isFullScreen = mDesc.fullscreen;
-			mIsChild = false;
+			mWindow->resize(width, height);
 
-			WINDOW_DESC windowDesc;
-			windowDesc.x = mDesc.left;
-			windowDesc.y = mDesc.top;
-			windowDesc.width = mDesc.videoMode.getWidth();
-			windowDesc.height = mDesc.videoMode.getHeight();
-			windowDesc.title = mDesc.title;
-			windowDesc.showDecorations = mDesc.showTitleBar;
-			windowDesc.allowResize = mDesc.allowResize;
-			windowDesc.modal = mDesc.modal;
-
-			auto iter = mDesc.platformSpecific.find("parentWindowHandle");
-			mIsChild = iter != mDesc.platformSpecific.end();
+			Rect2I area = mWindow->getArea();
+			props.width = area.width;
+			props.height = area.height;
 
-			props.isFullScreen = mDesc.fullscreen && !mIsChild;
+			{
+				ScopedSpinLock lock(getCore()->mLock);
+				getCore()->getSyncedProperties().width = width;
+				getCore()->getSyncedProperties().height = height;
+			}
 
-			mShowOnSwap = mDesc.hideUntilSwap;
-			props.isHidden = mDesc.hideUntilSwap || mDesc.hidden;
+			bs::RenderWindowManager::instance().notifySyncDataDirty(getCore().get());
+			onResized();
+		}
+	}
 
-			mWindow = bs_new<CocoaWindow>(windowDesc);
-			mWindow->_setUserData(this);
+	void MacOSRenderWindow::move(INT32 left, INT32 top)
+	{
+		RenderWindowProperties& props = mProperties;
+		if (!props.isFullScreen)
+		{
+			mWindow->move(left, top);
 
 			Rect2I area = mWindow->getArea();
-			props.width = area.width;
-			props.height = area.height;
 			props.top = area.y;
 			props.left = area.x;
 
-			props.hwGamma = mDesc.gamma;
-			props.multisampleCount = mDesc.multisampleCount;
+			{
+				ScopedSpinLock lock(getCore()->mLock);
+				getCore()->getSyncedProperties().top = props.top;
+				getCore()->getSyncedProperties().left = props.left;
+			}
 
-			mContext = mGLSupport.createContext(mDesc.depthBuffer, mDesc.multisampleCount);
+			bs::RenderWindowManager::instance().notifySyncDataDirty(getCore().get());
+		}
+	}
 
-			if(mDesc.fullscreen && !mIsChild)
-				setFullscreen(mDesc.videoMode);
+	void MacOSRenderWindow::hide()
+	{
+		getMutableProperties().isHidden = true;
+		{
+			ScopedSpinLock lock(getCore()->mLock);
+			getCore()->getSyncedProperties().isHidden = true;
+		}
 
-			if(mDesc.vsync && mDesc.vsyncInterval > 0)
-				setVSync(true, mDesc.vsyncInterval);
+		bs::RenderWindowManager::instance().notifySyncDataDirty(getCore().get());
+		mWindow->hide();
+	}
 
-			mScreenArea = mWindow->_getScreenArea();
-			mNativeWindowArea = mWindow->_getScreenArea();
+	void MacOSRenderWindow::show()
+	{
+		getMutableProperties().isHidden = false;
+		{
+			ScopedSpinLock lock(getCore()->mLock);
+			getCore()->getSyncedProperties().isHidden = false;
+		}
 
-			{
-				ScopedSpinLock lock(mLock);
-				mSyncedProperties = props;
-			}
+		bs::RenderWindowManager::instance().notifySyncDataDirty(getCore().get());
+		mWindow->show();
+	}
 
-			bs::RenderWindowManager::instance().notifySyncDataDirty(this);
-			RenderWindow::initialize();
+	void MacOSRenderWindow::minimize()
+	{
+		RenderWindowProperties& props = mProperties;
+		props.isMaximized = false;
+		{
+			ScopedSpinLock lock(getCore()->mLock);
+			getCore()->getSyncedProperties().isMaximized = false;
 		}
 
-		void MacOSRenderWindow::setFullscreen(UINT32 width, UINT32 height, float refreshRate, UINT32 monitorIdx)
-		{
-			THROW_IF_NOT_CORE_THREAD;
+		bs::RenderWindowManager::instance().notifySyncDataDirty(getCore().get());
+		mWindow->minimize();
+	}
 
-			VideoMode videoMode(width, height, refreshRate, monitorIdx);
-			setFullscreen(videoMode);
+	void MacOSRenderWindow::maximize()
+	{
+		RenderWindowProperties& props = mProperties;
+		props.isMaximized = true;
+		{
+			ScopedSpinLock lock(getCore()->mLock);
+			getCore()->getSyncedProperties().isMaximized = true;
 		}
 
-		void MacOSRenderWindow::setFullscreen(const VideoMode& mode)
+		bs::RenderWindowManager::instance().notifySyncDataDirty(getCore().get());
+		mWindow->maximize();
+	}
+
+	void MacOSRenderWindow::restore()
+	{
+		RenderWindowProperties& props = mProperties;
+		props.isMaximized = false;
 		{
-			THROW_IF_NOT_CORE_THREAD;
+			ScopedSpinLock lock(getCore()->mLock);
+			getCore()->getSyncedProperties().isMaximized = false;
+		}
 
-			if (mIsChild)
-				return;
+		bs::RenderWindowManager::instance().notifySyncDataDirty(getCore().get());
+		mWindow->restore();
+	}
 
-			const VideoModeInfo& videoModeInfo = RenderAPI::instance().getVideoModeInfo();
+	void MacOSRenderWindow::setFullscreen(UINT32 width, UINT32 height, float refreshRate, UINT32 monitorIdx)
+	{
+		VideoMode videoMode(width, height, refreshRate, monitorIdx);
+		setFullscreen(videoMode);
+	}
 
-			UINT32 outputIdx = mode.getOutputIdx();
-			if(outputIdx >= videoModeInfo.getNumOutputs())
-			{
-				LOGERR("Invalid output device index.")
-				return;
-			}
+	void MacOSRenderWindow::setFullscreen(const VideoMode& videoMode)
+	{
+		if (mIsChild)
+			return;
 
-			const VideoOutputInfo& outputInfo = videoModeInfo.getOutputInfo (outputIdx);
+		const VideoModeInfo& videoModeInfo = ct::RenderAPI::instance().getVideoModeInfo();
 
-			if(!mode.isCustom())
-				setDisplayMode(outputInfo, mode);
-			else
-			{
-				// Look for mode matching the requested resolution
-				UINT32 foundMode = (UINT32)-1;
-				UINT32 numModes = outputInfo.getNumVideoModes();
-				for (UINT32 i = 0; i < numModes; i++)
-				{
-					const VideoMode& currentMode = outputInfo.getVideoMode(i);
+		UINT32 outputIdx = videoMode.getOutputIdx();
+		if(outputIdx >= videoModeInfo.getNumOutputs())
+		{
+			LOGERR("Invalid output device index.")
+			return;
+		}
 
-					if (currentMode.getWidth() == mode.getWidth() && currentMode.getHeight() == mode.getHeight())
-					{
-						foundMode = i;
+		const VideoOutputInfo& outputInfo = videoModeInfo.getOutputInfo (outputIdx);
 
-						if (Math::approxEquals(currentMode.getRefreshRate(), mode.getRefreshRate()))
-							break;
-					}
-				}
+		if(!videoMode.isCustom())
+			setDisplayMode(outputInfo, videoMode);
+		else
+		{
+			// Look for mode matching the requested resolution
+			UINT32 foundMode = (UINT32)-1;
+			UINT32 numModes = outputInfo.getNumVideoModes();
+			for (UINT32 i = 0; i < numModes; i++)
+			{
+				const VideoMode& currentMode = outputInfo.getVideoMode(i);
 
-				if (foundMode == (UINT32)-1)
+				if (currentMode.getWidth() == videoMode.getWidth() && currentMode.getHeight() == videoMode.getHeight())
 				{
-					LOGERR("Unable to enter fullscreen, unsupported video mode requested.");
-					return;
+					foundMode = i;
+
+					if (Math::approxEquals(currentMode.getRefreshRate(), videoMode.getRefreshRate()))
+						break;
 				}
+			}
 
-				setDisplayMode(outputInfo, outputInfo.getVideoMode(foundMode));
+			if (foundMode == (UINT32)-1)
+			{
+				LOGERR("Unable to enter fullscreen, unsupported video mode requested.");
+				return;
 			}
 
-			mWindow->setFullscreen();
+			setDisplayMode(outputInfo, outputInfo.getVideoMode(foundMode));
+		}
 
-			RenderWindowProperties& props = mProperties;
-			props.isFullScreen = true;
+		mWindow->setFullscreen();
 
-			props.top = 0;
-			props.left = 0;
-			props.width = mode.getWidth();
-			props.height = mode.getHeight();
+		RenderWindowProperties& props = mProperties;
+		props.isFullScreen = true;
 
-			_windowMovedOrResized();
-		}
+		props.top = 0;
+		props.left = 0;
+		props.width = videoMode.getWidth();
+		props.height = videoMode.getHeight();
 
-		void MacOSRenderWindow::setWindowed(UINT32 width, UINT32 height)
 		{
-			THROW_IF_NOT_CORE_THREAD;
+			ScopedSpinLock lock(getCore()->mLock);
+			getCore()->getSyncedProperties().top = props.top;
+			getCore()->getSyncedProperties().left = props.left;
+			getCore()->getSyncedProperties().width = props.width;
+			getCore()->getSyncedProperties().height = props.height;
+		}
 
-			RenderWindowProperties& props = mProperties;
+		bs::RenderWindowManager::instance().notifySyncDataDirty(getCore().get());
+		_windowMovedOrResized();
+	}
 
-			if (!props.isFullScreen)
-				return;
+	void MacOSRenderWindow::setWindowed(UINT32 width, UINT32 height)
+	{
+		RenderWindowProperties& props = mProperties;
 
-			// Restore original display mode
-			const VideoModeInfo& videoModeInfo = RenderAPI::instance().getVideoModeInfo();
+		if (!props.isFullScreen)
+			return;
 
-			UINT32 outputIdx = 0; // 0 is always primary
-			if(outputIdx >= videoModeInfo.getNumOutputs())
-			{
-				LOGERR("Invalid output device index.")
-				return;
-			}
+		// Restore original display mode
+		const VideoModeInfo& videoModeInfo = ct::RenderAPI::instance().getVideoModeInfo();
 
-			const VideoOutputInfo& outputInfo = videoModeInfo.getOutputInfo(outputIdx);
-			setDisplayMode(outputInfo, outputInfo.getDesktopVideoMode());
+		UINT32 outputIdx = 0; // 0 is always primary
+		if(outputIdx >= videoModeInfo.getNumOutputs())
+		{
+			LOGERR("Invalid output device index.")
+			return;
+		}
 
-			mWindow->setWindowed();
+		const VideoOutputInfo& outputInfo = videoModeInfo.getOutputInfo(outputIdx);
+		setDisplayMode(outputInfo, outputInfo.getDesktopVideoMode());
 
-			props.isFullScreen = false;
-			props.width = width;
-			props.height = height;
+		mWindow->setWindowed();
 
-			{
-				ScopedSpinLock lock(mLock);
-				mSyncedProperties.width = props.width;
-				mSyncedProperties.height = props.height;
-			}
+		props.isFullScreen = false;
+		props.width = width;
+		props.height = height;
 
-			bs::RenderWindowManager::instance().notifySyncDataDirty(this);
-			_windowMovedOrResized();
+		{
+			ScopedSpinLock lock(getCore()->mLock);
+			getCore()->getSyncedProperties().width = props.width;
+			getCore()->getSyncedProperties().height = props.height;
 		}
 
-		void MacOSRenderWindow::setDisplayMode(const VideoOutputInfo& output, const VideoMode& mode)
+		bs::RenderWindowManager::instance().notifySyncDataDirty(getCore().get());
+		_windowMovedOrResized();
+	}
+
+	void MacOSRenderWindow::setDisplayMode(const VideoOutputInfo& output, const VideoMode& mode)
+	{
+		CGDisplayFadeReservationToken fadeToken = kCGDisplayFadeReservationInvalidToken;
+		if (CGAcquireDisplayFadeReservation(5.0f, &fadeToken))
+			CGDisplayFade(fadeToken, 0.3f, kCGDisplayBlendNormal, kCGDisplayBlendSolidColor, 0, 0, 0, TRUE);
+
+		auto& destOutput = static_cast<const ct::MacOSVideoOutputInfo&>(output);
+		auto& newMode = static_cast<const ct::MacOSVideoMode&>(mode);
+		auto& desktopMode = static_cast<const ct::MacOSVideoMode&>(output.getDesktopVideoMode());
+
+		CGDirectDisplayID displayID = destOutput._getDisplayID();
+
+		if (desktopMode._getModeRef() == newMode._getModeRef())
 		{
-			CGDisplayFadeReservationToken fadeToken = kCGDisplayFadeReservationInvalidToken;
-			if (CGAcquireDisplayFadeReservation(5.0f, &fadeToken))
-				CGDisplayFade(fadeToken, 0.3f, kCGDisplayBlendNormal, kCGDisplayBlendSolidColor, 0, 0, 0, TRUE);
+			CGDisplaySetDisplayMode(displayID, newMode._getModeRef(), nullptr);
 
-			auto& destOutput = static_cast<const MacOSVideoOutputInfo&>(output);
-			auto& newMode = static_cast<const MacOSVideoMode&>(mode);
-			auto& desktopMode = static_cast<const MacOSVideoMode&>(output.getDesktopVideoMode());
+			if (CGDisplayIsMain(displayID))
+				CGReleaseAllDisplays();
+			else
+				CGDisplayRelease(displayID);
+		}
+		else
+		{
+			CGError status;
+			if (CGDisplayIsMain(displayID))
+				status = CGCaptureAllDisplays();
+			else
+				status = CGDisplayCapture(displayID);
 
-			CGDirectDisplayID displayID = destOutput._getDisplayID();
+			if (status != kCGErrorSuccess)
+				goto UNFADE;
 
-			if (desktopMode._getModeRef() == newMode._getModeRef())
+			status = CGDisplaySetDisplayMode(displayID, newMode._getModeRef(), nullptr);
+			if(status != kCGErrorSuccess)
 			{
-				CGDisplaySetDisplayMode(displayID, newMode._getModeRef(), nullptr);
-
 				if (CGDisplayIsMain(displayID))
 					CGReleaseAllDisplays();
 				else
 					CGDisplayRelease(displayID);
-			}
-			else
-			{
-				CGError status;
-				if (CGDisplayIsMain(displayID))
-					status = CGCaptureAllDisplays();
-				else
-					status = CGDisplayCapture(displayID);
 
-				if (status != kCGErrorSuccess)
-					goto UNFADE;
-
-				status = CGDisplaySetDisplayMode(displayID, newMode._getModeRef(), nullptr);
-				if(status != kCGErrorSuccess)
-				{
-					if (CGDisplayIsMain(displayID))
-						CGReleaseAllDisplays();
-					else
-						CGDisplayRelease(displayID);
-
-					goto UNFADE;
-				}
-			}
-
-			UNFADE:
-			if (fadeToken != kCGDisplayFadeReservationInvalidToken)
-			{
-				CGDisplayFade(fadeToken, 0.3f, kCGDisplayBlendSolidColor, kCGDisplayBlendNormal, 0, 0, 0, FALSE);
-				CGReleaseDisplayFadeReservation(fadeToken);
+				goto UNFADE;
 			}
 		}
 
-		void MacOSRenderWindow::move(INT32 left, INT32 top)
+		UNFADE:
+		if (fadeToken != kCGDisplayFadeReservationInvalidToken)
 		{
-			THROW_IF_NOT_CORE_THREAD;
-
-			RenderWindowProperties& props = mProperties;
-			if (!props.isFullScreen)
-			{
-				mWindow->move(left, top);
-
-				Rect2I area = mWindow->getArea();
-				props.top = area.y;
-				props.left = area.x;
-
-				{
-					ScopedSpinLock lock(mLock);
-					mSyncedProperties.top = props.top;
-					mSyncedProperties.left = props.left;
-				}
-
-				mScreenArea = mWindow->_getScreenArea();
-				mNativeWindowArea = mWindow->_getScreenArea();
-
-				bs::RenderWindowManager::instance().notifySyncDataDirty(this);
-			}
+			CGDisplayFade(fadeToken, 0.3f, kCGDisplayBlendSolidColor, kCGDisplayBlendNormal, 0, 0, 0, FALSE);
+			CGReleaseDisplayFadeReservation(fadeToken);
 		}
+	}
 
-		void MacOSRenderWindow::resize(UINT32 width, UINT32 height)
+	void MacOSRenderWindow::getCustomAttribute(const String& name, void* data) const
+	{
+		if(name == "WINDOW" || name == "COCOA_WINDOW")
 		{
-			THROW_IF_NOT_CORE_THREAD;
-
-			RenderWindowProperties& props = mProperties;
-			if (!props.isFullScreen)
-			{
-				mWindow->resize(width, height);
+			blockUntilCoreInitialized();
+			getCore()->getCustomAttribute(name, data);
+			return;
+		}
+	}
 
-				Rect2I area = mWindow->getArea();
-				props.width = area.width;
-				props.height = area.height;
+	Vector2I MacOSRenderWindow::screenToWindowPos(const Vector2I& screenPos) const
+	{
+		return mWindow->screenToWindowPos(screenPos);
+	}
 
-				{
-					ScopedSpinLock lock(mLock);
-					mSyncedProperties.width = props.width;
-					mSyncedProperties.height = props.height;
-				}
+	Vector2I MacOSRenderWindow::windowToScreenPos(const Vector2I& windowPos) const
+	{
+		return mWindow->windowToScreenPos(windowPos);
+	}
 
-				mScreenArea = mWindow->_getScreenArea();
-				mNativeWindowArea = mWindow->_getScreenArea();
+	SPtr<ct::MacOSRenderWindow> MacOSRenderWindow::getCore() const
+	{
+		return std::static_pointer_cast<ct::MacOSRenderWindow>(mCoreSpecific);
+	}
 
-				bs::RenderWindowManager::instance().notifySyncDataDirty(this);
-			}
-		}
+	void MacOSRenderWindow::_windowMovedOrResized()
+	{
+		if (!mWindow)
+			return;
 
-		void MacOSRenderWindow::minimize()
+		RenderWindowProperties& props = mProperties;
+		if (!props.isFullScreen) // Fullscreen is handled directly by this object
 		{
-			THROW_IF_NOT_CORE_THREAD;
+			Rect2I area = mWindow->getArea();
 
-			mWindow->minimize();
+			props.top = area.y;
+			props.left = area.x;
+			props.width = area.width;
+			props.height = area.height;
 		}
 
-		void MacOSRenderWindow::maximize()
 		{
-			THROW_IF_NOT_CORE_THREAD;
-
-			mWindow->maximize();
+			ScopedSpinLock lock(getCore()->mLock);
+			getCore()->getSyncedProperties().top = props.top;
+			getCore()->getSyncedProperties().left = props.left;
+			getCore()->getSyncedProperties().width = props.width;
+			getCore()->getSyncedProperties().height = props.height;
 		}
 
-		void MacOSRenderWindow::restore()
+		mContext->markAsDirty();
+	}
+
+	void MacOSRenderWindow::syncProperties()
+	{
+		ScopedSpinLock lock(getCore()->_getPropertiesLock());
+		mProperties = getCore()->mSyncedProperties;
+	}
+
+	namespace ct
+	{
+		MacOSRenderWindow::MacOSRenderWindow(const RENDER_WINDOW_DESC& desc, UINT32 windowId, MacOSGLSupport& glsupport)
+			: RenderWindow(desc, windowId), mWindow(nullptr), mContext(nullptr), mGLSupport(glsupport), mProperties(desc)
+			, mSyncedProperties(desc), mShowOnSwap(false)
+		{ }
+
+		void MacOSRenderWindow::move(INT32 left, INT32 top)
 		{
-			THROW_IF_NOT_CORE_THREAD;
+			// Do nothing
+		}
 
-			mWindow->restore();
+		void MacOSRenderWindow::resize(UINT32 width, UINT32 height)
+		{
+			// Do nothing
 		}
 
 		void MacOSRenderWindow::setVSync(bool enabled, UINT32 interval)
@@ -467,57 +526,11 @@ namespace bs
 				*window = mWindow;
 				return;
 			}
-		}
-
-		void MacOSRenderWindow::setActive(bool state)
-		{
-			THROW_IF_NOT_CORE_THREAD;
-
-			if(state)
-				mWindow->restore();
-			else
-				mWindow->minimize();
-
-			RenderWindow::setActive(state);
-		}
-
-		void MacOSRenderWindow::setHidden(bool hidden)
-		{
-			THROW_IF_NOT_CORE_THREAD;
-
-			if(!hidden)
-				mShowOnSwap = false;
-
-			if(hidden)
-				mWindow->hide();
-			else
-				mWindow->show();
-
-			RenderWindow::setHidden(hidden);
-		}
-
-		void MacOSRenderWindow::_windowMovedOrResized()
-		{
-			if (!mWindow)
-				return;
-
-			Lock lock(mDimensionsMutex);
-
-			RenderWindowProperties& props = mProperties;
-			if (!props.isFullScreen) // Fullscreen is handled directly by this object
+			else if(name == "WINDOW_ID")
 			{
-				Rect2I area = mWindow->getArea();
-
-				props.top = area.y;
-				props.left = area.x;
-				props.width = area.width;
-				props.height = area.height;
+				UINT32* windowId = (UINT32*)data;
+				*windowId = mWindow->_getWindowId();
 			}
-
-			mScreenArea = mWindow->_getScreenArea();
-			mNativeWindowArea = mWindow->getArea(false);
-
-			RenderWindow::_windowMovedOrResized();
 		}
 
 		void MacOSRenderWindow::syncProperties()

+ 8 - 2
Source/BansheeGLRenderAPI/MacOS/BsMacOSVideoModeInfo.cpp

@@ -13,6 +13,8 @@ namespace bs::ct
 		CGGetOnlineDisplayList(0, nullptr, &numDisplays);
 
 		auto displays = (CGDirectDisplayID*)bs_stack_alloc(sizeof(CGDirectDisplayID) * numDisplays);
+		CGGetOnlineDisplayList(numDisplays, displays, &numDisplays);
+
 		for(UINT32 i = 0; i < numDisplays; i++)
 		{
 			if(CGDisplayMirrorsDisplay(displays[i]) != kCGNullDirectDisplay)
@@ -43,7 +45,7 @@ namespace bs::ct
 
 		io_service_t service = CGDisplayIOServicePort(displayID);
 		CFDictionaryRef deviceInfo = IODisplayCreateInfoDictionary(service, kIODisplayOnlyPreferredName);
-		auto locNames = (CFDictionaryRef)CFDictionaryGetValue(deviceInfo, kDisplayProductName);
+		auto locNames = (CFDictionaryRef)CFDictionaryGetValue(deviceInfo, CFSTR(kDisplayProductName));
 
 		CFIndex numNames = CFDictionaryGetCount(locNames);
 		if(numNames > 0)
@@ -51,10 +53,14 @@ namespace bs::ct
 			auto keys = (CFStringRef*)bs_stack_alloc(numNames * sizeof(CFTypeRef));
 			CFDictionaryGetKeysAndValues(locNames, (const void**)keys, nullptr);
 
-			mName = CFStringGetCStringPtr(keys[0], kCFStringEncodingUTF8);
+			CFStringRef value = (CFStringRef)CFDictionaryGetValue(locNames, keys[0]);
+			mName = CFStringGetCStringPtr(value, kCFStringEncodingUTF8);
+
 			bs_stack_free(keys);
 		}
 
+		CFRelease(deviceInfo);
+
 		mDesktopVideoMode = new (bs_alloc<MacOSVideoMode>()) MacOSVideoMode(desktopModeRef, linkRef, outputIdx);
 
 		CFArrayRef modes = CGDisplayCopyAllDisplayModes(displayID, nullptr);

+ 0 - 6
Source/BansheeMono/BsMonoArray.cpp

@@ -42,12 +42,6 @@ namespace bs
 			void** item = (void**)ScriptArray::_getArrayAddr(array, sizeof(void*), idx);
 			*item = nullptr;
 		}
-
-		template String ScriptArray_get(MonoArray* array, UINT32 idx);
-		template WString ScriptArray_get(MonoArray* array, UINT32 idx);
-
-		template void ScriptArray_set(MonoArray* array, UINT32 idx, const String& value);
-		template void ScriptArray_set(MonoArray* array, UINT32 idx, const WString& value);
 	}
 
 	ScriptArray::ScriptArray(MonoArray* existingArray)

+ 1 - 1
Source/BansheeUtility/Allocators/BsFrameAlloc.cpp

@@ -285,7 +285,7 @@ namespace bs
 	void FrameAlloc::deallocBlock(MemBlock* block)
 	{
 		block->~MemBlock();
-		bs_free_aligned(block);
+		bs_free_aligned16(block);
 	}
 
 	void FrameAlloc::setOwnerThread(ThreadId thread)