Browse Source

WIP: Linux port
- Fixing window close logic so it properly cleans up instead of just crashing
- Window close events originating from the OS can now be handled by the user instead of just shutting down the app
- Fixing an issue where few script wrappers weren't initialized on startup
- Fixing file browse dialog by properly initializing GTK before first use

Marko Pintera 8 years ago
parent
commit
07c160bb50

+ 10 - 29
Source/BansheeCore/Linux/BsLinuxPlatform.cpp

@@ -53,7 +53,6 @@ namespace bs
 		::Window mainXWindow = 0;
 		::Window fullscreenXWindow = 0;
 		UnorderedMap<::Window, LinuxWindow*> windowMap;
-		Vector<::Window> toDestroy;
 		Mutex lock;
 
 		XIM IM;
@@ -736,17 +735,9 @@ namespace bs
 		while(true)
 		{
 			Lock lock(mData->lock);
-			if(XPending(mData->xDisplay) <= 0)
-			{
-				// No more events, destroy any queued windows
-				for(auto& entry : mData->toDestroy)
-					XDestroyWindow(mData->xDisplay, entry);
-
-				mData->toDestroy.clear();
-				XSync(mData->xDisplay, false);
 
+			if(XPending(mData->xDisplay) <= 0)
 				break;
-			}
 
 			XEvent event;
 			XNextEvent(mData->xDisplay, &event);
@@ -758,28 +749,18 @@ namespace bs
 				if(LinuxDragAndDrop::handleClientMessage(event.xclient))
 					break;
 
+				// User requested the window to close
 				if((Atom)event.xclient.data.l[0] == mData->atomDeleteWindow)
 				{
-					// We queue the window for destruction as soon as we process all current events (since some of those
-					// events could still refer to this window)
-					mData->toDestroy.push_back(event.xclient.window);
-
-					XUnmapWindow(mData->xDisplay, event.xclient.window);
-					XSync(mData->xDisplay, false);
-				}
-			}
-				break;
-			case DestroyNotify:
-			{
-				LinuxWindow* window = getLinuxWindow(mData, event.xdestroywindow.window);
-				if(window != nullptr)
-				{
-					window->_cleanUp();
-
-					if (mData->mainXWindow == 0)
+					LinuxWindow* window = getLinuxWindow(mData, event.xclient.window);
+					if(window != nullptr)
 					{
-						CoreApplication::instance().quitRequested();
-						return;
+						// If it's a render window we allow the client code to handle the message
+						ct::RenderWindow* renderWindow = (ct::RenderWindow*)window->_getUserData();
+						if(renderWindow != nullptr)
+							renderWindow->_notifyCloseRequested();
+						else // If not, we just destroy the window
+							window->_destroy();
 					}
 				}
 			}

+ 8 - 10
Source/BansheeCore/Linux/BsLinuxWindow.cpp

@@ -227,15 +227,7 @@ namespace bs
 	LinuxWindow::~LinuxWindow()
 	{
 		if(m->xWindow != 0)
-		{
-			XUnmapWindow(LinuxPlatform::getXDisplay(), m->xWindow);
-			XSync(LinuxPlatform::getXDisplay(), 0);
-
-			XDestroyWindow(LinuxPlatform::getXDisplay(), m->xWindow);
-			XSync(LinuxPlatform::getXDisplay(), 0);
-
-			_cleanUp();
-		}
+			_destroy();
 
 		bs_delete(m);
 	}
@@ -374,8 +366,14 @@ namespace bs
 		XFreePixmap(display, iconPixmap);
 	}
 
-	void LinuxWindow::_cleanUp()
+	void LinuxWindow::_destroy()
 	{
+		XUnmapWindow(LinuxPlatform::getXDisplay(), m->xWindow);
+		XSync(LinuxPlatform::getXDisplay(), 0);
+
+		XDestroyWindow(LinuxPlatform::getXDisplay(), m->xWindow);
+		XSync(LinuxPlatform::getXDisplay(), 0);
+
 		LinuxPlatform::_unregisterWindow(m->xWindow);
 		m->xWindow = 0;
 	}

+ 5 - 2
Source/BansheeCore/Linux/BsLinuxWindow.h

@@ -91,8 +91,11 @@ namespace bs
 		 * @{
 		 */
 
-		/** Unregisters the window from the manager. Should be called before the window is destroyed. */
-		void _cleanUp();
+		/**
+		 * 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.
+		 */
+		void _destroy();
 
 		/**
 		 * Sets a portion of the window in which the user can click and drag in order to move the window. This is needed

+ 29 - 3
Source/BansheeCore/Managers/BsRenderWindowManager.cpp

@@ -2,6 +2,7 @@
 //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
 #include "Managers/BsRenderWindowManager.h"
 #include "Platform/BsPlatform.h"
+#include "BsCoreApplication.h"
 
 using namespace std::placeholders;
 
@@ -112,6 +113,17 @@ namespace bs
 			mMouseLeftWindows.push_back(window);
 	}
 
+	void RenderWindowManager::notifyCloseRequested(ct::RenderWindow* coreWindow)
+	{
+		Lock lock(mWindowMutex);
+
+		RenderWindow* window = getNonCore(coreWindow);
+		auto iterFind = std::find(begin(mCloseRequestedWindows), end(mCloseRequestedWindows), window);
+
+		if (iterFind == end(mCloseRequestedWindows))
+			mCloseRequestedWindows.push_back(window);
+	}
+
 	void RenderWindowManager::notifySyncDataDirty(ct::RenderWindow* coreWindow)
 	{
 		Lock lock(mWindowMutex);
@@ -127,6 +139,7 @@ namespace bs
 		RenderWindow* newWinInFocus = nullptr;
 		Vector<MoveOrResizeData> movedOrResizedWindows;
 		Vector<RenderWindow*> mouseLeftWindows;
+		Vector<RenderWindow*> closeRequestedWindows;
 
 		{
 			Lock lock(mWindowMutex);
@@ -156,6 +169,8 @@ namespace bs
 				dirtyPropertyWindow->syncProperties();
 
 			mDirtyProperties.clear();
+
+			std::swap(mCloseRequestedWindows, closeRequestedWindows);
 		}
 
 		if(mWindowInFocus != newWinInFocus)
@@ -170,15 +185,26 @@ namespace bs
 		}
 
 		for (auto& moveResizeData : movedOrResizedWindows)
-		{
 			moveResizeData.window->onResized();
-		}
 
 		if (!onMouseLeftWindow.empty())
 		{
 			for (auto& window : mouseLeftWindows)
 				onMouseLeftWindow(*window);
-		}			
+		}
+
+		SPtr<RenderWindow> primaryWindow = gCoreApplication().getPrimaryWindow();
+		for(auto& entry : closeRequestedWindows)
+		{
+			// Default behaviour for primary window is to quit the app on close
+			if(entry == primaryWindow.get() && entry->onCloseRequested.empty())
+			{
+				gCoreApplication().quitRequested();
+				continue;
+			}
+
+			entry->onCloseRequested();
+		}
 	}
 
 	Vector<RenderWindow*> RenderWindowManager::getRenderWindows() const

+ 4 - 0
Source/BansheeCore/Managers/BsRenderWindowManager.h

@@ -52,6 +52,9 @@ namespace bs
 		/**	Called by the core thread when mouse leaves a window. */
 		void notifyMouseLeft(ct::RenderWindow* window);
 
+		/** Called by the core thread when the user requests for the window to close. */
+		void notifyCloseRequested(ct::RenderWindow* coreWindow);
+
 		/**	Called by the sim thread when window properties change. */
 		void notifySyncDataDirty(ct::RenderWindow* coreWindow);
 
@@ -83,6 +86,7 @@ namespace bs
 		RenderWindow* mNewWindowInFocus;
 		Vector<MoveOrResizeData> mMovedOrResizedWindows;
 		Vector<RenderWindow*> mMouseLeftWindows;
+		Vector<RenderWindow*> mCloseRequestedWindows;
 		UnorderedSet<RenderWindow*> mDirtyProperties;
 	};
 

+ 7 - 0
Source/BansheeCore/RenderAPI/BsRenderWindow.cpp

@@ -364,6 +364,13 @@ namespace bs
 		bs::RenderWindowManager::instance().notifyMouseLeft(this);
 	}
 
+	void RenderWindow::_notifyCloseRequested()
+	{
+		THROW_IF_NOT_CORE_THREAD;
+
+		bs::RenderWindowManager::instance().notifyCloseRequested(this);
+	}
+
 	const RenderWindowProperties& RenderWindow::getProperties() const
 	{
 		return static_cast<const RenderWindowProperties&>(getPropertiesInternal());

+ 9 - 0
Source/BansheeCore/RenderAPI/BsRenderWindow.h

@@ -180,6 +180,9 @@ namespace bs
 		 */
 		static SPtr<RenderWindow> create(RENDER_WINDOW_DESC& desc, SPtr<RenderWindow> parentWindow = nullptr);
 
+		/** 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;
+
 	protected:
 		friend class RenderWindowManager;
 
@@ -328,6 +331,12 @@ namespace bs
 		 */
 		virtual void _notifyMouseLeft();
 
+		/**
+		 * Called when the users requests for the window to be closed.
+		 *
+		 * @note	Core thread.
+		 */
+		virtual void _notifyCloseRequested();
 	protected:
 		friend class bs::RenderWindow;
 		friend class RenderWindowManager;

+ 1 - 2
Source/BansheeCore/Win32/BsWin32Platform.cpp

@@ -419,7 +419,6 @@ namespace bs
 				"in performance for waiting threads.");
 		}
 
-
 		mData->mRequiresStartUp = true;
 	}
 
@@ -700,7 +699,7 @@ namespace bs
 			break;
 		case WM_CLOSE:
 			{
-				gCoreApplication().quitRequested();
+				win->_notifyCloseRequested();
 
 				return 0;
 			}

+ 7 - 0
Source/BansheeEditor/Linux/BsLinuxBrowseDialogs.cpp

@@ -11,6 +11,13 @@ namespace bs
 	bool EditorUtility::openBrowseDialog(FileDialogType type, const Path& defaultPath, const String& filterList,
 									Vector<Path>& paths)
 	{
+		static bool gtkInitialized = false;
+		if(!gtkInitialized)
+		{
+			gtk_init(nullptr, nullptr);
+			gtkInitialized = true;
+		}
+
 		GtkWidget* fakeParent = gtk_window_new(GTK_WINDOW_TOPLEVEL);
 
 		const char* titleString;

+ 0 - 1
Source/Examples/ExamplePhysicallyBasedShading/ObjectRotator.cpp

@@ -53,7 +53,6 @@ namespace bs
 
 		// If we're rotating, apply new pitch/yaw rotation values depending on the amount of rotation from the
 		// vertical/horizontal axes.
-		float frameDelta = gTime().getFrameDelta();
 		if (isRotating)
 		{
 			mYaw -= Degree(gVirtualInput().getAxisValue(mHorizontalAxis) * ROTATION_SPEED);

+ 4 - 0
Source/SBansheeEditor/Wrappers/BsScriptBrowseDialog.cpp

@@ -9,6 +9,10 @@
 
 namespace bs
 {
+	ScriptBrowseDialog::ScriptBrowseDialog(MonoObject* instance)
+			:ScriptObject(instance)
+	{ }
+
 	void ScriptBrowseDialog::initRuntimeData()
 	{
 		metaData.scriptClass->addInternalCall("Internal_OpenFile", (void*)&ScriptBrowseDialog::internal_OpenFile);

+ 1 - 0
Source/SBansheeEditor/Wrappers/BsScriptBrowseDialog.h

@@ -18,6 +18,7 @@ namespace bs
 		SCRIPT_OBJ(EDITOR_ASSEMBLY, "BansheeEditor", "BrowseDialog")
 
 	private:
+		ScriptBrowseDialog(MonoObject* instance);
 
 		/************************************************************************/
 		/* 								CLR HOOKS						   		*/

+ 4 - 0
Source/SBansheeEditor/Wrappers/BsScriptGizmos.cpp

@@ -12,6 +12,10 @@
 
 namespace bs
 {
+	ScriptGizmos::ScriptGizmos(MonoObject* instance)
+		:ScriptObject(instance)
+	{ }
+
 	void ScriptGizmos::initRuntimeData()
 	{
 		metaData.scriptClass->addInternalCall("Internal_SetColor", (void*)&ScriptGizmos::internal_SetColor);

+ 2 - 0
Source/SBansheeEditor/Wrappers/BsScriptGizmos.h

@@ -23,6 +23,8 @@ namespace bs
 		SCRIPT_OBJ(EDITOR_ASSEMBLY, "BansheeEditor", "Gizmos")
 
 	private:
+		ScriptGizmos(MonoObject* instance);
+
 		/************************************************************************/
 		/* 								CLR HOOKS						   		*/
 		/************************************************************************/

+ 4 - 0
Source/SBansheeEditor/Wrappers/BsScriptHandleDrawing.cpp

@@ -11,6 +11,10 @@
 
 namespace bs
 {
+	ScriptHandleDrawing::ScriptHandleDrawing(MonoObject* instance)
+		:ScriptObject(instance)
+	{ }
+
 	void ScriptHandleDrawing::initRuntimeData()
 	{
 		metaData.scriptClass->addInternalCall("Internal_SetColor", (void*)&ScriptHandleDrawing::internal_SetColor);

+ 2 - 0
Source/SBansheeEditor/Wrappers/BsScriptHandleDrawing.h

@@ -22,6 +22,8 @@ namespace bs
 		SCRIPT_OBJ(EDITOR_ASSEMBLY, "BansheeEditor", "HandleDrawing")
 
 	private:
+		ScriptHandleDrawing(MonoObject* instance);
+
 		/************************************************************************/
 		/* 								CLR HOOKS						   		*/
 		/************************************************************************/

+ 2 - 2
Source/SBansheeEditor/Wrappers/BsScriptPrefabUtility.h

@@ -18,6 +18,8 @@ namespace bs
 		SCRIPT_OBJ(EDITOR_ASSEMBLY, "BansheeEditor", "PrefabUtility")
 
 	private:
+		ScriptPrefabUtility(MonoObject* instance);
+
 		/************************************************************************/
 		/* 								CLR HOOKS						   		*/
 		/************************************************************************/
@@ -29,8 +31,6 @@ namespace bs
 		static MonoString* internal_GetPrefabUUID(ScriptSceneObject* soPtr);
 		static void internal_UpdateFromPrefab(ScriptSceneObject* soPtr);
 		static void internal_RecordPrefabDiff(ScriptSceneObject* soPtr);
-
-		ScriptPrefabUtility(MonoObject* instance);
 	};
 
 	/** @} */

+ 4 - 0
Source/SBansheeEditor/Wrappers/BsScriptUnitTests.cpp

@@ -14,6 +14,10 @@ namespace bs
 	MonoMethod* ScriptUnitTests::RunTestsMethod;
 	SPtr<ManagedSerializableDiff> ScriptUnitTests::tempDiff;
 
+	ScriptUnitTests::ScriptUnitTests(MonoObject* instance)
+		:ScriptObject(instance)
+	{ }
+
 	void ScriptUnitTests::initRuntimeData()
 	{
 		metaData.scriptClass->addInternalCall("Internal_UT1_GameObjectClone", (void*)&ScriptUnitTests::internal_UT1_GameObjectClone);

+ 2 - 1
Source/SBansheeEditor/Wrappers/BsScriptUnitTests.h

@@ -21,8 +21,9 @@ namespace bs
 		static void runTests();
 
 	private:
-		static MonoMethod* RunTestsMethod;
+		ScriptUnitTests(MonoObject* instance);
 
+		static MonoMethod* RunTestsMethod;
 		static SPtr<ManagedSerializableDiff> tempDiff;
 
 		/************************************************************************/