Browse Source

Merge minor into default, next release shall be 0.9.0

Bart van Strien 12 years ago
parent
commit
a9244da013
51 changed files with 1510 additions and 1620 deletions
  1. 10 1
      changes.txt
  2. 0 3
      platform/unix/exclude
  3. 2 3
      src/common/Object.h
  4. 1 11
      src/common/delay.cpp
  5. 0 2
      src/common/delay.h
  6. 10 4
      src/common/runtime.cpp
  7. 9 0
      src/common/runtime.h
  8. 2 0
      src/common/types.h
  9. 10 2
      src/modules/audio/openal/Audio.cpp
  10. 4 4
      src/modules/audio/openal/Audio.h
  11. 1 1
      src/modules/audio/openal/Pool.cpp
  12. 6 0
      src/modules/event/Event.cpp
  13. 2 2
      src/modules/event/Event.h
  14. 7 0
      src/modules/event/sdl/Event.cpp
  15. 12 10
      src/modules/graphics/opengl/Graphics.cpp
  16. 6 8
      src/modules/graphics/opengl/Graphics.h
  17. 71 13
      src/modules/graphics/opengl/wrap_Graphics.cpp
  18. 12 0
      src/modules/image/ImageData.cpp
  19. 4 2
      src/modules/image/ImageData.h
  20. 7 1
      src/modules/image/devil/ImageData.cpp
  21. 5 0
      src/modules/image/devil/ImageData.h
  22. 241 0
      src/modules/thread/Channel.cpp
  23. 75 0
      src/modules/thread/Channel.h
  24. 68 0
      src/modules/thread/LuaThread.cpp
  25. 52 0
      src/modules/thread/LuaThread.h
  26. 0 317
      src/modules/thread/Thread.cpp
  27. 11 91
      src/modules/thread/Thread.h
  28. 48 0
      src/modules/thread/ThreadModule.cpp
  29. 52 0
      src/modules/thread/ThreadModule.h
  30. 0 192
      src/modules/thread/posix/threads.cpp
  31. 0 107
      src/modules/thread/posix/threads.h
  32. 92 0
      src/modules/thread/sdl/Thread.cpp
  33. 57 0
      src/modules/thread/sdl/Thread.h
  34. 25 86
      src/modules/thread/sdl/threads.cpp
  35. 14 50
      src/modules/thread/sdl/threads.h
  36. 39 16
      src/modules/thread/threads.cpp
  37. 43 45
      src/modules/thread/threads.h
  38. 0 211
      src/modules/thread/win32/threads.cpp
  39. 0 107
      src/modules/thread/win32/threads.h
  40. 131 0
      src/modules/thread/wrap_Channel.cpp
  41. 44 0
      src/modules/thread/wrap_Channel.h
  42. 71 0
      src/modules/thread/wrap_LuaThread.cpp
  43. 7 19
      src/modules/thread/wrap_LuaThread.h
  44. 0 290
      src/modules/thread/wrap_Thread.cpp
  45. 126 0
      src/modules/thread/wrap_ThreadModule.cpp
  46. 40 0
      src/modules/thread/wrap_ThreadModule.h
  47. 11 2
      src/modules/window/Window.h
  48. 34 8
      src/modules/window/sdl/Window.cpp
  49. 4 2
      src/modules/window/sdl/Window.h
  50. 13 1
      src/scripts/boot.lua
  51. 31 9
      src/scripts/boot.lua.h

+ 10 - 1
changes.txt

@@ -1,4 +1,4 @@
-LOVE 0.8.1 [Rubber Piggy]
+LOVE 0.9.0 []
 --------------
 
   * Added --fused command line argument, to simulate fusing.
@@ -18,6 +18,12 @@ LOVE 0.8.1 [Rubber Piggy]
   * Added boolean support to Shader:send.
   * Added support for UTF-8 ImageFonts.
   * Added SoundData:getDuration.
+  * Added new Channels api for love.thread.
+  * Added flags to setMode.
+  * Added support for resizable and borderless windows.
+  * Added resize event.
+  * Added love.math module.
+  * Added a platform-independent (good) random implementation to love.math.
   * OPTIONAL: Added support for GME.
 
   * Fixed crashes with font drawing on some ATI cards.
@@ -45,6 +51,9 @@ LOVE 0.8.1 [Rubber Piggy]
 
   * Removed love.joystick.open and friends.
   * Removed love.graphics.drawTest.
+  * Removed thread names.
+  * Removed old thread messaging api (see Channels).
+  * Removed love.graphics.quad/triangle.
 
   * Updated allocation for SoundData, it's more efficient and less wasteful.
   * Updated Source:set* functions to default z to 0.

+ 0 - 3
platform/unix/exclude

@@ -21,7 +21,4 @@
 \./modules/native/tcc/libtcc/stab\.h
 \./libraries/luasocket/libluasocket/wsocket\.*
 \./modules/sound/lullaby/FLACDecoder\.*
-\./modules/thread/sdl/*
-\./modules/thread/win32/*
-\./modules/thread/posix/*
 \./love\.cpp

+ 2 - 3
src/common/Object.h

@@ -56,21 +56,20 @@ public:
 	 * Retains the Object, i.e. increases the
 	 * reference count by one.
 	 **/
-	void retain();
+	virtual void retain();
 
 	/**
 	 * Releases one reference to the Object, i.e. decrements the
 	 * reference count by one, and potentially deletes the Object
 	 * if there are no more references.
 	 **/
-	void release();
+	virtual void release();
 
 private:
 
 	// The reference count.
 	int count;
 }; // Object
-
 } // love
 
 #endif // LOVE_OBJECT_H

+ 1 - 11
src/common/delay.cpp

@@ -19,24 +19,14 @@
  **/
 
 #include "delay.h"
+#include <SDL.h>
 
 namespace love
 {
 
 void delay(unsigned int ms)
 {
-#if LOVE_THREADS == LOVE_THREADS_POSIX
-	struct timespec ts1, ts2;
-
-	ts1.tv_sec = ms / 1000;
-	ts1.tv_nsec = (ms % 1000) * 1000000;
-	// FIXME: handle signals
-	nanosleep(&ts1, &ts2);
-#elif LOVE_THREADS == LOVE_THREADS_WIN32
-	Sleep(ms);
-#elif LOVE_THREADS == LOVE_THREADS_SDL
 	SDL_Delay(ms);
-#endif
 }
 
 } // love

+ 0 - 2
src/common/delay.h

@@ -21,8 +21,6 @@
 #ifndef DELAY_H_
 #define DELAY_H_
 
-#include <thread/threads.h>
-
 namespace love
 {
 

+ 10 - 4
src/common/runtime.cpp

@@ -25,7 +25,7 @@
 #include "Object.h"
 #include "Reference.h"
 #include "StringMap.h"
-#include "thread/threads.h"
+#include <thread/threads.h>
 
 // STD
 #include <iostream>
@@ -35,7 +35,6 @@ namespace love
 
 static thread::Mutex *gcmutex = 0;
 void *_gcmutex = 0;
-unsigned int _gcthread = 0;
 /**
  * Called when an object is collected. The object is released
  * once in this function, possibly deleting it.
@@ -44,7 +43,7 @@ static int w__gc(lua_State *L)
 {
 	if (!gcmutex)
 	{
-		gcmutex = new thread::Mutex();
+		gcmutex = thread::newMutex();
 		_gcmutex = (void *) gcmutex;
 	}
 	Proxy *p = (Proxy *)lua_touserdata(L, 1);
@@ -52,7 +51,6 @@ static int w__gc(lua_State *L)
 	if (p->own)
 	{
 		thread::Lock lock(gcmutex);
-		_gcthread = thread::ThreadBase::threadId();
 		t->release();
 	}
 	return 0;
@@ -118,6 +116,13 @@ bool luax_optboolean(lua_State *L, int idx, bool b)
 	return b;
 }
 
+std::string luax_tostring(lua_State *L, int idx)
+{
+	size_t len;
+	const char *str = lua_tolstring(L, idx, &len);
+	return std::string(str, len);
+}
+
 std::string luax_checkstring(lua_State *L, int idx)
 {
 	size_t len;
@@ -489,6 +494,7 @@ StringMap<Type, TYPE_MAX_ENUM>::Entry typeEntries[] =
 
 	// Thread
 	{"Thread", THREAD_THREAD_ID},
+	{"Channel", THREAD_CHANNEL_ID},
 
 	// The modules themselves. Only add abstracted modules here.
 	{"filesystem", MODULE_FILESYSTEM_ID},

+ 9 - 0
src/common/runtime.h

@@ -132,6 +132,15 @@ void luax_pushboolean(lua_State *L, bool b);
  **/
 bool luax_optboolean(lua_State *L, int idx, bool b);
 
+/**
+ * Converts the value at idx to a std::string. It takes care of the string
+ * size and possible embedded nulls.
+ * @param L The Lua state.
+ * @param idx The index on the Lua stack.
+ * @return Copy of the string at the specified index.
+ **/
+std::string luax_tostring(lua_State *L, int idx);
+
 /**
  * Converts the value at idx to a std::string. It takes care of the string
  * size and possible embedded nulls.

+ 2 - 0
src/common/types.h

@@ -89,6 +89,7 @@ enum Type
 
 	// Thread
 	THREAD_THREAD_ID,
+	THREAD_CHANNEL_ID,
 
 	// The modules themselves. Only add abstracted modules here.
 	MODULE_FILESYSTEM_ID,
@@ -160,6 +161,7 @@ const bits PHYSICS_WHEEL_JOINT_T = (bits(1) << PHYSICS_WHEEL_JOINT_ID) | PHYSICS
 
 // Thread.
 const bits THREAD_THREAD_T = (bits(1) << THREAD_THREAD_ID) | OBJECT_T;
+const bits THREAD_CHANNEL_T = (bits(1) << THREAD_CHANNEL_ID) | OBJECT_T;
 
 // Modules.
 const bits MODULE_FILESYSTEM_T = (bits(1) << MODULE_FILESYSTEM_ID) | MODULE_T;

+ 10 - 2
src/modules/audio/openal/Audio.cpp

@@ -23,6 +23,8 @@
 
 #include "sound/Decoder.h"
 
+#include <cstdlib>
+
 namespace love
 {
 namespace audio
@@ -34,9 +36,16 @@ Audio::PoolThread::PoolThread(Pool *pool)
 	: pool(pool)
 	, finish(false)
 {
+	mutex = thread::newMutex();
+}
+
+Audio::PoolThread::~PoolThread()
+{
+	delete mutex;
 }
 
-void Audio::PoolThread::main()
+
+void Audio::PoolThread::threadFunction()
 {
 	while (true)
 	{
@@ -59,7 +68,6 @@ void Audio::PoolThread::setFinish()
 	finish = true;
 }
 
-
 Audio::Audio() : distanceModel(DISTANCE_INVERSE_CLAMPED)
 {
 	// Passing zero for default device.

+ 4 - 4
src/modules/audio/openal/Audio.h

@@ -109,7 +109,7 @@ private:
 	// The Pool.
 	Pool *pool;
 
-	class PoolThread: public thread::ThreadBase
+	class PoolThread: public thread::Threadable
 	{
 	protected:
 		Pool *pool;
@@ -120,13 +120,13 @@ private:
 		volatile bool finish;
 
 		// finish lock
-		thread::Mutex mutex;
-
-		virtual void main();
+		thread::Mutex *mutex;
 
 	public:
 		PoolThread(Pool *pool);
+		~PoolThread();
 		void setFinish();
+		void threadFunction();
 	};
 
 	PoolThread *poolThread;

+ 1 - 1
src/modules/audio/openal/Pool.cpp

@@ -35,7 +35,7 @@ Pool::Pool()
 	alGenSources(NUM_SOURCES, sources);
 
 	// Create the mutex.
-	mutex = new thread::Mutex();
+	mutex = thread::newMutex();
 
 	if (alGetError() != AL_NO_ERROR)
 		throw love::Exception("Could not generate sources.");

+ 6 - 0
src/modules/event/Event.cpp

@@ -80,8 +80,14 @@ Message *Message::fromLua(lua_State *L, int n)
 	return m;
 }
 
+Event::Event()
+{
+	mutex = thread::newMutex();
+}
+
 Event::~Event()
 {
+	delete mutex;
 }
 
 void Event::push(Message *msg)

+ 2 - 2
src/modules/event/Event.h

@@ -54,6 +54,7 @@ public:
 class Event : public Module
 {
 public:
+	Event();
 	virtual ~Event();
 
 	void push(Message *msg);
@@ -68,13 +69,12 @@ public:
 	static bool getConstant(love::keyboard::Keyboard::Key in, const char  *&out);
 
 protected:
-	thread::Mutex mutex;
+	thread::Mutex *mutex;
 	std::queue<Message *> queue;
 	static StringMap<love::mouse::Mouse::Button, love::mouse::Mouse::BUTTON_MAX_ENUM>::Entry buttonEntries[];
 	static StringMap<love::mouse::Mouse::Button, love::mouse::Mouse::BUTTON_MAX_ENUM> buttons;
 	static StringMap<love::keyboard::Keyboard::Key, love::keyboard::Keyboard::KEY_MAX_ENUM>::Entry keyEntries[];
 	static StringMap<love::keyboard::Keyboard::Key, love::keyboard::Keyboard::KEY_MAX_ENUM> keys;
-
 }; // Event
 
 } // event

+ 7 - 0
src/modules/event/sdl/Event.cpp

@@ -144,6 +144,13 @@ Message *Event::convert(SDL_Event &e)
 	case SDL_QUIT:
 		msg = new Message("quit");
 		break;
+	case SDL_VIDEORESIZE:
+		arg1 = new Variant((double) e.resize.w);
+		arg2 = new Variant((double) e.resize.h);
+		msg = new Message("resize", arg1, arg2);
+		arg1->release();
+		arg2->release();
+		break;
 	}
 
 	return msg;

+ 12 - 10
src/modules/graphics/opengl/Graphics.cpp

@@ -30,6 +30,8 @@
 #include <algorithm>
 #include <iterator>
 
+using love::window::WindowFlags;
+
 namespace love
 {
 namespace graphics
@@ -103,7 +105,7 @@ void Graphics::restoreState(const DisplayState &s)
 		setScissor();
 }
 
-bool Graphics::setMode(int width, int height, bool fullscreen, bool vsync, int fsaa)
+bool Graphics::setMode(int width, int height, WindowFlags *flags)
 {
 	// This operation destroys the OpenGL context, so
 	// we must save the state.
@@ -117,14 +119,13 @@ bool Graphics::setMode(int width, int height, bool fullscreen, bool vsync, int f
 
 	uninitializeContext();
 
-	bool success = currentWindow->setWindow(width, height, fullscreen, vsync, fsaa);
-	// Regardless of failure, we'll have to set up OpenGL once again.
+	bool success = currentWindow->setWindow(width, height, flags);
 
+	// Regardless of failure, we'll have to set up OpenGL once again.
 	width = currentWindow->getWidth();
 	height = currentWindow->getHeight();
 
 	// Okay, setup OpenGL.
-
 	initializeContext();
 
 	// Make sure antialiasing works when set elsewhere
@@ -181,17 +182,18 @@ bool Graphics::setMode(int width, int height, bool fullscreen, bool vsync, int f
 	return success;
 }
 
-void Graphics::getMode(int &width, int &height, bool &fullscreen, bool &vsync, int &fsaa) const
+void Graphics::getMode(int &width, int &height, WindowFlags &flags) const
 {
-	currentWindow->getWindow(width, height, fullscreen, vsync, fsaa);
+	currentWindow->getWindow(width, height, flags);
 }
 
 bool Graphics::toggleFullscreen()
 {
-	int width, height, fsaa;
-	bool fullscreen, vsync;
-	currentWindow->getWindow(width, height, fullscreen, vsync, fsaa);
-	return setMode(width, height, !fullscreen, vsync, fsaa);
+	int width, height;
+	WindowFlags flags;
+	currentWindow->getWindow(width, height, flags);
+	flags.fullscreen = !flags.fullscreen;
+	return setMode(width, height, &flags);
 }
 
 

+ 6 - 8
src/modules/graphics/opengl/Graphics.h

@@ -45,6 +45,8 @@
 #include "Canvas.h"
 #include "Shader.h"
 
+using love::window::WindowFlags;
+
 namespace love
 {
 namespace graphics
@@ -127,21 +129,17 @@ public:
 	 * Sets the current display mode.
 	 * @param width The window width.
 	 * @param height The window height.
-	 * @param fullscreen True if fullscreen, false otherwise.
-	 * @param vsync True if we should wait for vsync, false otherwise.
-	 * @param fsaa Number of full scene anti-aliasing buffer, or 0 for disabled.
+	 * @param flags An optional WindowFlags structure.
 	 **/
-	bool setMode(int width, int height, bool fullscreen, bool vsync, int fsaa);
+	bool setMode(int width, int height, WindowFlags *flags);
 
 	/**
 	 * Gets the current display mode.
 	 * @param width Pointer to an integer for the window width.
 	 * @param height Pointer to an integer for the window height.
-	 * @param fullscreen Pointer to a boolean for the fullscreen status.
-	 * @param vsync Pointer to a boolean for the vsync status.
-	 * @param fsaa Pointer to an integer for the current number of full scene anti-aliasing buffers.
+	 * @param flags A WindowFlags structure.
 	 **/
-	void getMode(int &width, int &height, bool &fullscreen, bool &vsync, int &fsaa) const;
+	void getMode(int &width, int &height, WindowFlags &flags) const;
 
 	/**
 	 * Toggles fullscreen. Note that this also needs to reload the

+ 71 - 13
src/modules/graphics/opengl/wrap_Graphics.cpp

@@ -27,6 +27,8 @@
 #include "scripts/graphics.lua.h"
 #include <cassert>
 
+using love::window::WindowFlags;
+
 namespace love
 {
 namespace graphics
@@ -36,6 +38,34 @@ namespace opengl
 
 static Graphics *instance = 0;
 
+bool luax_boolflag(lua_State *L, int table_index, const char *key, bool defaultValue)
+{
+	lua_getfield(L, table_index, key);
+
+	bool retval;
+	if (lua_isnoneornil(L, -1))
+		retval = defaultValue;
+	else
+		retval = lua_toboolean(L, -1);
+
+	lua_pop(L, 1);
+	return retval;
+}
+
+int luax_intflag(lua_State *L, int table_index, const char *key, int defaultValue)
+{
+	lua_getfield(L, table_index, key);
+
+	int retval;
+	if (!lua_isnumber(L, -1))
+		retval = defaultValue;
+	else
+		retval = lua_tonumber(L, -1);
+
+	lua_pop(L, 1);
+	return retval;
+}
+
 int w_checkMode(lua_State *L)
 {
 	int w = luaL_checkint(L, 1);
@@ -49,24 +79,52 @@ int w_setMode(lua_State *L)
 {
 	int w = luaL_checkint(L, 1);
 	int h = luaL_checkint(L, 2);
-	bool fs = luax_optboolean(L, 3, false);
-	bool vsync = luax_optboolean(L, 4, true);
-	int fsaa = luaL_optint(L, 5, 0);
-	luax_pushboolean(L, instance->setMode(w, h, fs, vsync, fsaa));
+	if (lua_isnoneornil(L, 3))
+	{
+		luax_pushboolean(L, instance->setMode(w, h, 0));
+		return 1;
+	}
+
+	luaL_checktype(L, 3, LUA_TTABLE);
+
+	WindowFlags flags;
+
+	flags.fullscreen = luax_boolflag(L, 3, "fullscreen", false);
+	flags.vsync = luax_boolflag(L, 3, "vsync", true);
+	flags.fsaa = luax_intflag(L, 3, "fsaa", 0);
+	flags.resizable = luax_boolflag(L, 3, "resizable", false);
+	flags.borderless = luax_boolflag(L, 3, "borderless", false);
+
+	luax_pushboolean(L, instance->setMode(w, h, &flags));
 	return 1;
 }
 
 int w_getMode(lua_State *L)
 {
-	int w, h, fsaa;
-	bool fs, vsync;
-	instance->getMode(w, h, fs, vsync, fsaa);
+	int w, h;
+	WindowFlags flags;
+	instance->getMode(w, h, flags);
 	lua_pushnumber(L, w);
 	lua_pushnumber(L, h);
-	lua_pushboolean(L, fs);
-	lua_pushboolean(L, vsync);
-	lua_pushnumber(L, fsaa);
-	return 5;
+
+	lua_newtable(L);
+
+	luax_pushboolean(L, flags.fullscreen);
+	lua_setfield(L, -2, "fullscreen");
+
+	luax_pushboolean(L, flags.vsync);
+	lua_setfield(L, -2, "vsync");
+
+	lua_pushnumber(L, flags.fsaa);
+	lua_setfield(L, -2, "fsaa");
+
+	luax_pushboolean(L, flags.resizable);
+	lua_setfield(L, -2, "resizable");
+
+	luax_pushboolean(L, flags.borderless);
+	lua_setfield(L, -2, "borderless");
+
+	return 3;
 }
 
 int w_toggleFullscreen(lua_State *L)
@@ -1350,9 +1408,9 @@ static const luaL_Reg functions[] =
 
 	{ "point", w_point },
 	{ "line", w_line },
-	{ "triangle", w_triangle },
+	//{ "triangle", w_triangle },
 	{ "rectangle", w_rectangle },
-	{ "quad", w_quad },
+	//{ "quad", w_quad },
 	{ "circle", w_circle },
 	{ "arc", w_arc },
 

+ 12 - 0
src/modules/image/ImageData.cpp

@@ -20,6 +20,8 @@
 
 #include "ImageData.h"
 
+#include <stdio.h>
+
 using love::thread::Lock;
 
 namespace love
@@ -27,6 +29,16 @@ namespace love
 namespace image
 {
 
+ImageData::ImageData()
+{
+	mutex = thread::newMutex();
+}
+
+ImageData::~ImageData()
+{
+	delete mutex;
+}
+
 void *ImageData::getData() const
 {
 	return data;

+ 4 - 2
src/modules/image/ImageData.h

@@ -59,7 +59,7 @@ protected:
 	// We need to be thread-safe
 	// so we lock when we're accessing our
 	// data
-	Mutex mutex;
+	Mutex *mutex;
 
 public:
 
@@ -73,10 +73,12 @@ public:
 		FORMAT_MAX_ENUM
 	};
 
+	ImageData();
+
 	/**
 	 * Destructor.
 	 **/
-	virtual ~ImageData() {};
+	virtual ~ImageData();
 
 	static bool getConstant(const char *in, Format &out);
 	static bool getConstant(Format in, const char  *&out);

+ 7 - 1
src/modules/image/devil/ImageData.cpp

@@ -31,7 +31,7 @@
 
 using love::thread::Lock;
 
-static Mutex devilMutex;
+static Mutex *devilMutex = 0;
 
 namespace love
 {
@@ -96,6 +96,9 @@ void ImageData::create(int width, int height, void *data)
 
 void ImageData::load(Data *data)
 {
+	if (!devilMutex)
+		devilMutex = thread::newMutex();
+
 	Lock lock(devilMutex);
 	ILuint image;
 	ilGenImages(1, &image);
@@ -132,6 +135,9 @@ void ImageData::load(Data *data)
 
 void ImageData::encode(love::filesystem::File *f, ImageData::Format format)
 {
+	if (!devilMutex)
+		devilMutex = thread::newMutex();
+
 	Lock lock1(devilMutex);
 	Lock lock2(mutex);
 

+ 5 - 0
src/modules/image/devil/ImageData.h

@@ -57,6 +57,11 @@ public:
 	// Implements ImageData.
 	void encode(love::filesystem::File *f, Format format);
 
+	// We need to be thread-safe
+	// so we lock when we're accessing our
+	// data
+	Mutex *mutex;
+
 }; // ImageData
 
 } // devil

+ 241 - 0
src/modules/thread/Channel.cpp

@@ -0,0 +1,241 @@
+/**
+* Copyright (c) 2006-2012 LOVE Development Team
+*
+* This software is provided 'as-is', without any express or implied
+* warranty.  In no event will the authors be held liable for any damages
+* arising from the use of this software.
+*
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+*
+* 1. The origin of this software must not be misrepresented; you must not
+*    claim that you wrote the original software. If you use this software
+*    in a product, an acknowledgment in the product documentation would be
+*    appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+*    misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+**/
+
+#include "Channel.h"
+#include <map>
+#include <string>
+
+namespace
+{
+union uslong
+{
+	unsigned long u;
+	long i;
+};
+
+// target <= current, but semi-wrapsafe, one wrap, anyway
+inline bool past(unsigned int target, unsigned int current)
+{
+	if (target > current)
+		return false;
+	if (target == current)
+		return true;
+
+	uslong t, c;
+	t.u = target;
+	c.u = current;
+
+	return !(t.i < 0 && c.i > 0);
+}
+}
+
+namespace love
+{
+namespace thread
+{
+static std::map<std::string, Channel *> namedChannels;
+static Mutex *namedChannelMutex;
+
+Channel *Channel::getChannel(const std::string &name)
+{
+	if (!namedChannelMutex)
+		namedChannelMutex = newMutex();
+
+	Lock l(namedChannelMutex);
+	if (!namedChannels.count(name))
+		namedChannels[name] = new Channel(name);
+	else
+		namedChannels[name]->retain();
+
+	return namedChannels[name];
+}
+
+Channel::Channel()
+	: named(false)
+	, sent(0)
+	, received(0)
+{
+	mutex = newMutex();
+	cond = newConditional();
+}
+
+Channel::Channel(const std::string &name)
+	: named(true)
+	, name(name)
+	, sent(0)
+	, received(0)
+{
+	mutex = newMutex();
+	cond = newConditional();
+}
+
+Channel::~Channel()
+{
+	while (!queue.empty())
+	{
+		queue.front()->release();
+		queue.pop();
+	}
+
+	delete mutex;
+	delete cond;
+
+	if (named)
+		namedChannels.erase(name);
+}
+
+unsigned long Channel::push(Variant *var)
+{
+	if (!var)
+		return 0;
+
+	Lock l(mutex);
+	var->retain();
+
+	// Keep a reference to ourselves
+	// if we're non-empty and named.
+	if (named && queue.empty())
+		retain();
+
+	queue.push(var);
+	cond->broadcast();
+
+	return ++sent;
+}
+
+void Channel::supply(Variant *var)
+{
+	if (!var)
+		return;
+
+	mutex->lock();
+	unsigned long id = push(var);
+
+	while (!past(id, received))
+		cond->wait(mutex);
+
+	mutex->unlock();
+}
+
+Variant *Channel::pop()
+{
+	Lock l(mutex);
+	if (queue.empty())
+		return 0;
+
+	Variant *var = queue.front();
+	queue.pop();
+
+	received++;
+	cond->broadcast();
+
+	// Release our reference to ourselves
+	// if we're empty and named.
+	if (named && queue.empty())
+		release();
+
+	return var;
+} // NOTE: Returns a retained Variant
+
+Variant *Channel::demand()
+{
+	Variant *var;
+	mutex->lock();
+	while (!(var = pop()))
+		cond->wait(mutex);
+
+	mutex->unlock();
+	return var;
+}
+
+Variant *Channel::peek()
+{
+	Lock l(mutex);
+	if (queue.empty())
+		return 0;
+
+	Variant *var = queue.front();
+	var->retain();
+	return var;
+}
+
+int Channel::count()
+{
+	Lock l(mutex);
+	return queue.size();
+}
+
+void Channel::clear()
+{
+	Lock l(mutex);
+
+	// We're already empty.
+	if (queue.empty())
+		return;
+
+	while (!queue.empty())
+	{
+		queue.front()->release();
+		queue.pop();
+	}
+
+	// Finish all the supply waits
+	received = sent;
+	cond->broadcast();
+
+	// Once again, release our own
+	// reference if we're named.
+	if (named)
+		release();
+}
+
+void Channel::lockMutex()
+{
+	mutex->lock();
+}
+
+void Channel::unlockMutex()
+{
+	mutex->unlock();
+}
+
+void Channel::retain()
+{
+	if (named)
+		namedChannelMutex->lock();
+
+	Object::retain();
+
+	if (named)
+		namedChannelMutex->unlock();
+}
+
+void Channel::release()
+{
+	if (named)
+		namedChannelMutex->lock();
+
+	Object::release();
+
+	if (named)
+		namedChannelMutex->unlock();
+}
+} // thread
+} // love

+ 75 - 0
src/modules/thread/Channel.h

@@ -0,0 +1,75 @@
+/**
+* Copyright (c) 2006-2012 LOVE Development Team
+*
+* This software is provided 'as-is', without any express or implied
+* warranty.  In no event will the authors be held liable for any damages
+* arising from the use of this software.
+*
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+*
+* 1. The origin of this software must not be misrepresented; you must not
+*    claim that you wrote the original software. If you use this software
+*    in a product, an acknowledgment in the product documentation would be
+*    appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+*    misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+**/
+
+#ifndef LOVE_THREAD_CHANNEL_H
+#define LOVE_THREAD_CHANNEL_H
+
+// STL
+#include <queue>
+#include <string>
+
+// LOVE
+#include <common/Variant.h>
+#include <thread/threads.h>
+
+namespace love
+{
+namespace thread
+{
+class Channel : public love::Object
+{
+// FOR WRAPPER USE ONLY
+friend void retainVariant(Channel *, Variant *);
+friend void releaseVariant(Channel *, Variant *);
+
+public:
+	Channel();
+	~Channel();
+	static Channel *getChannel(const std::string &name);
+
+	unsigned long push(Variant *var);
+	void supply(Variant *var); // blocking push
+	Variant *pop();
+	Variant *demand(); // blocking pop
+	Variant *peek();
+	int count();
+	void clear();
+
+	void retain();
+	void release();
+
+private:
+	Channel(const std::string &name);
+	void lockMutex();
+	void unlockMutex();
+
+	Mutex *mutex;
+	Conditional *cond;
+	std::queue<Variant *> queue;
+	bool named;
+	std::string name;
+
+	unsigned long sent;
+	unsigned long received;
+}; // Channel
+} // thread
+} // love
+
+#endif // LOVE_THREAD_CHANNEL_H

+ 68 - 0
src/modules/thread/LuaThread.cpp

@@ -0,0 +1,68 @@
+/**
+* Copyright (c) 2006-2012 LOVE Development Team
+*
+* This software is provided 'as-is', without any express or implied
+* warranty.  In no event will the authors be held liable for any damages
+* arising from the use of this software.
+*
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+*
+* 1. The origin of this software must not be misrepresented; you must not
+*    claim that you wrote the original software. If you use this software
+*    in a product, an acknowledgment in the product documentation would be
+*    appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+*    misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+**/
+
+#include "LuaThread.h"
+#include <common/config.h>
+
+#ifdef LOVE_BUILD_STANDALONE
+extern "C" int luaopen_love(lua_State * L);
+#endif // LOVE_BUILD_STANDALONE
+extern "C" int luaopen_love_thread(lua_State *L);
+
+namespace love
+{
+namespace thread
+{
+LuaThread::LuaThread(const std::string &name, love::Data *code)
+	: name(name), code(code)
+{
+	code->retain();
+}
+
+LuaThread::~LuaThread()
+{
+	code->release();
+}
+
+void LuaThread::threadFunction()
+{
+	this->retain();
+	lua_State * L = lua_open();
+	luaL_openlibs(L);
+#ifdef LOVE_BUILD_STANDALONE
+	love::luax_preload(L, luaopen_love, "love");
+	luaopen_love(L);
+#endif // LOVE_BUILD_STANDALONE
+	luaopen_love_thread(L);
+	if (luaL_loadbuffer(L, (const char *) code->getData(), code->getSize(), name.c_str()) != 0)
+		error = luax_tostring(L, -1);
+	else
+		if (lua_pcall(L, 0, 0, 0) != 0)
+			error = luax_tostring(L, -1);
+	lua_close(L);
+	this->release();
+}
+
+const std::string &LuaThread::getError()
+{
+	return error;
+}
+} // thread
+} // love

+ 52 - 0
src/modules/thread/LuaThread.h

@@ -0,0 +1,52 @@
+/**
+* Copyright (c) 2006-2012 LOVE Development Team
+*
+* This software is provided 'as-is', without any express or implied
+* warranty.  In no event will the authors be held liable for any damages
+* arising from the use of this software.
+*
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+*
+* 1. The origin of this software must not be misrepresented; you must not
+*    claim that you wrote the original software. If you use this software
+*    in a product, an acknowledgment in the product documentation would be
+*    appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+*    misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+**/
+
+#ifndef LOVE_THREAD_LUATHREAD_H
+#define LOVE_THREAD_LUATHREAD_H
+
+// STL
+#include <string>
+
+// LOVE
+#include <common/Object.h>
+#include <common/Data.h>
+#include <thread/threads.h>
+
+namespace love
+{
+namespace thread
+{
+class LuaThread : public love::Object, public Threadable
+{
+public:
+	LuaThread(const std::string &name, love::Data *code);
+	~LuaThread();
+	void threadFunction();
+	const std::string &getError();
+
+private:
+	love::Data *code;
+	std::string name;
+	std::string error;
+};
+} // thread
+} // love
+
+#endif // LOVE_THREAD_LUATHREAD_H

+ 0 - 317
src/modules/thread/Thread.cpp

@@ -1,317 +0,0 @@
-/**
- * Copyright (c) 2006-2013 LOVE Development Team
- *
- * This software is provided 'as-is', without any express or implied
- * warranty.  In no event will the authors be held liable for any damages
- * arising from the use of this software.
- *
- * Permission is granted to anyone to use this software for any purpose,
- * including commercial applications, and to alter it and redistribute it
- * freely, subject to the following restrictions:
- *
- * 1. The origin of this software must not be misrepresented; you must not
- *    claim that you wrote the original software. If you use this software
- *    in a product, an acknowledgment in the product documentation would be
- *    appreciated but is not required.
- * 2. Altered source versions must be plainly marked as such, and must not be
- *    misrepresented as being the original software.
- * 3. This notice may not be removed or altered from any source distribution.
- **/
-
-#include "common/config.h"
-
-#include "Thread.h"
-
-#ifdef LOVE_BUILD_STANDALONE
-extern "C" int luaopen_love(lua_State *L);
-#endif // LOVE_BUILD_STANDALONE
-extern "C" int luaopen_love_thread(lua_State *L);
-
-namespace love
-{
-namespace thread
-{
-
-Thread::ThreadThread::ThreadThread(ThreadData *comm)
-	: comm(comm)
-{
-}
-
-void Thread::ThreadThread::main()
-{
-	lua_State *L = luaL_newstate();
-	luaL_openlibs(L);
-#ifdef LOVE_BUILD_STANDALONE
-	love::luax_preload(L, luaopen_love, "love");
-	luaopen_love(L);
-#endif // LOVE_BUILD_STANDALONE
-	luaopen_love_thread(L);
-	{
-		size_t len;
-		const char *name = comm->getName(&len);
-		lua_pushlstring(L, name, len);
-	}
-	luax_convobj(L, lua_gettop(L), "thread", "getThread");
-	lua_getglobal(L, "love");
-	lua_pushvalue(L, -2);
-	lua_setfield(L, -2, "_curthread");
-	if (luaL_dostring(L, comm->getCode()) == 1)
-	{
-		{
-			Lock lock((Mutex *) comm->mutex);
-			Variant *v = new Variant(lua_tostring(L, -1), lua_strlen(L, -1));
-			comm->setValue("error", v);
-			v->release();
-		}
-		((Conditional *) comm->cond)->broadcast();
-	}
-	lua_close(L);
-}
-
-ThreadData::ThreadData(const char *name, size_t len, const char *code, void *mutex, void *cond)
-	: mutex(mutex), cond(cond), len(len)
-{
-	this->name = new char[len+1];
-	memset(this->name, 0, len+1);
-	memcpy(this->name, name, len);
-	if (code)
-	{
-		len = strlen(code);
-		this->code = new char[len+1];
-		memset(this->code, 0, len+1);
-		memcpy(this->code, code, len);
-	}
-	else
-		this->code = 0;
-}
-
-ThreadData::~ThreadData()
-{
-	delete[] name;
-	delete[] code;
-}
-
-const char *ThreadData::getCode()
-{
-	return code;
-}
-
-const char *ThreadData::getName(size_t *len)
-{
-	if (len)
-		 *len = this->len;
-	return name;
-}
-
-Variant *ThreadData::getValue(const std::string &name)
-{
-	if (shared.count(name) == 0)
-		return 0;
-	return shared[name];
-}
-
-void ThreadData::clearValue(const std::string &name)
-{
-	if (shared.count(name) == 0)
-		return;
-	shared[name]->release();
-	shared.erase(name);
-}
-
-void ThreadData::setValue(const std::string &name, Variant *v)
-{
-	if (shared.count(name) != 0)
-		shared[name]->release();
-	v->retain();
-	shared[name] = v;
-}
-
-std::vector<std::string> ThreadData::getKeys()
-{
-	std::vector<std::string> keys;
-	for (std::map<std::string, Variant *>::iterator it = shared.begin(); it != shared.end(); it++)
-	{
-		keys.push_back(it->first);
-	}
-	return keys;
-}
-
-Thread::Thread(love::thread::ThreadModule *module, const std::string &name, love::Data *data)
-	: handle(0), module(module), name(name), isThread(true)
-{
-	module->retain();
-	unsigned int len = data->getSize();
-	this->data = new char[len+1];
-	memset(this->data, 0, len+1);
-	memcpy(this->data, data->getData(), len);
-	mutex = new Mutex();
-	cond = new Conditional();
-	comm = new ThreadData(name.c_str(), name.length(), this->data, mutex, cond);
-}
-
-Thread::Thread(love::thread::ThreadModule *module, const std::string &name)
-	: handle(0), module(module), name(name), data(0), isThread(false)
-{
-	module->retain();
-	mutex = new Mutex();
-	cond = new Conditional();
-	comm = new ThreadData(name.c_str(), name.length(), NULL, mutex, cond);
-}
-
-Thread::~Thread()
-{
-	if (data)
-		delete[] data;
-	delete comm;
-	module->unregister(name);
-	delete mutex;
-	delete cond;
-	module->release();
-}
-
-void Thread::start()
-{
-	if (!handle && isThread)
-	{
-		handle = new ThreadThread(comm);
-		handle->start();
-	}
-}
-
-void Thread::kill()
-{
-	if (handle)
-	{
-		Lock lock((Mutex *) _gcmutex);
-		handle->kill();
-		delete handle;
-		handle = 0;
-	}
-}
-
-void Thread::wait()
-{
-	if (handle)
-	{
-		handle->wait();
-		delete handle;
-		handle = 0;
-	}
-}
-
-void Thread::lock()
-{
-	mutex->lock();
-}
-
-void Thread::unlock()
-{
-	mutex->unlock();
-}
-
-std::string Thread::getName()
-{
-	return name;
-}
-
-Variant *Thread::get(const std::string &name)
-{
-	Variant *v = comm->getValue(name);
-	if (v)
-		v->retain();
-	return v;
-}
-
-std::vector<std::string> Thread::getKeys()
-{
-	return comm->getKeys();
-}
-
-Variant *Thread::demand(const std::string &name)
-{
-	Variant *v = comm->getValue(name);
-	while (!v)
-	{
-		if (comm->getValue("error"))
-			return 0;
-		cond->wait(mutex);
-		v = comm->getValue(name);
-	}
-	v->retain();
-	return v;
-}
-
-void Thread::clear(const std::string &name)
-{
-	comm->clearValue(name);
-}
-
-void Thread::set(const std::string &name, Variant *v)
-{
-	lock(); //this function explicitly locks
-	comm->setValue(name, v); //because we need
-	unlock(); //it to unlock here for the cond
-	cond->broadcast();
-}
-
-ThreadModule::ThreadModule()
-{
-	threads["main"] = new Thread(this, "main");
-}
-
-ThreadModule::~ThreadModule()
-{
-	for (threadlist_t::iterator i = threads.begin(); i != threads.end(); i++)
-	{
-		i->second->kill();
-		delete i->second;
-	}
-}
-
-Thread *ThreadModule::newThread(const std::string &name, love::Data *data)
-{
-	if (threads.count(name) != 0)
-		return 0;
-	Thread *t = new Thread(this, name, data);
-	threads[name] = t;
-	return t;
-}
-
-Thread *ThreadModule::getThread(const std::string &name)
-{
-	if (threads.count(name) == 0)
-		return 0;
-	threadlist_t::iterator i = threads.find(name);
-	return i->second;
-}
-
-void ThreadModule::getThreads(Thread **list)
-{
-	int c = 0;
-	for (threadlist_t::iterator i = threads.begin(); i != threads.end(); i++, c++)
-	{
-		list[c] = i->second;
-	}
-}
-
-unsigned ThreadModule::getThreadCount() const
-{
-	return threads.size();
-}
-
-void ThreadModule::unregister(const std::string &name)
-{
-	if (threads.count(name) == 0)
-		return;
-	threadlist_t::iterator i = threads.find(name);
-	// FIXME: shouldn't the thread be deleted?
-	threads.erase(i);
-}
-
-const char *ThreadModule::getName() const
-{
-	return "love.thread.sdl";
-}
-
-} // thread
-} // love

+ 11 - 91
src/modules/thread/Thread.h

@@ -18,108 +18,28 @@
  * 3. This notice may not be removed or altered from any source distribution.
  **/
 
-#ifndef LOVE_THREAD_SDL_THREAD_H
-#define LOVE_THREAD_SDL_THREAD_H
-
-// STL
-#include <map>
-#include <string>
-#include <vector>
-#include <cstring>
+#ifndef LOVE_THREAD_THREAD_H
+#define LOVE_THREAD_THREAD_H
 
 // LOVE
-#include "filesystem/File.h"
-#include "common/runtime.h"
-#include "common/Module.h"
-#include "common/Variant.h"
-#include "thread/threads.h"
+#include <common/runtime.h>
+#include <common/Object.h>
 
 namespace love
 {
 namespace thread
 {
 
-class ThreadModule;
-
-class ThreadData
+class Thread
 {
 public:
-	ThreadData(const char *name, size_t len, const char *code, void *mutex, void *cond);
-	~ThreadData();
-	const char *getCode();
-	const char *getName(size_t *len = 0);
-	Variant *getValue(const std::string &name);
-	void clearValue(const std::string &name);
-	void setValue(const std::string &name, Variant *v);
-	std::vector<std::string> getKeys();
-
-	void *mutex;
-	void *cond;
-private:
-	char *code;
-	char *name;
-	std::map<std::string, Variant *> shared;
-	size_t len;
-};
-
-class Thread : public love::Object
-{
-public:
-	Thread(love::thread::ThreadModule *module, const std::string &name, love::Data *data);
-	Thread(love::thread::ThreadModule *module, const std::string &name);
-	virtual ~Thread();
-	void start();
-	void kill();
-	void wait();
-	std::string getName();
-	Variant *get(const std::string &name);
-	std::vector<std::string> getKeys();
-	Variant *demand(const std::string &name);
-	void clear(const std::string &name);
-	void set(const std::string &name, Variant *v);
-	void lock();
-	void unlock();
-private:
-	class ThreadThread: public ThreadBase
-	{
-	private:
-		ThreadData *comm;
-
-	protected:
-		virtual void main();
+	virtual ~Thread() {}
+	virtual bool start() = 0;
+	virtual void wait() = 0;
+	virtual void kill() = 0;
+}; // ThreadObject
 
-	public:
-		ThreadThread(ThreadData *comm);
-	};
-
-	ThreadThread *handle;
-
-	ThreadModule *module;
-	ThreadData *comm;
-	std::string name;
-	char *data;
-	Mutex *mutex;
-	Conditional *cond;
-	bool isThread;
-}; // Thread
-
-typedef std::map<std::string, Thread *> threadlist_t;
-
-class ThreadModule : public love::Module
-{
-public:
-	ThreadModule();
-	virtual ~ThreadModule();
-	Thread *newThread(const std::string &name, love::Data *data);
-	void getThreads(Thread **list);
-	Thread *getThread(const std::string &name);
-	unsigned getThreadCount() const;
-	void unregister(const std::string &name);
-	const char *getName() const;
-private:
-	threadlist_t threads;
-}; // ThreadModule
 } // thread
 } // love
 
-#endif // LOVE_THREAD_SDL_THREAD_H
+#endif // LOVE_THREAD_THREAD_H

+ 48 - 0
src/modules/thread/ThreadModule.cpp

@@ -0,0 +1,48 @@
+/**
+* Copyright (c) 2006-2012 LOVE Development Team
+*
+* This software is provided 'as-is', without any express or implied
+* warranty.  In no event will the authors be held liable for any damages
+* arising from the use of this software.
+*
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+*
+* 1. The origin of this software must not be misrepresented; you must not
+*    claim that you wrote the original software. If you use this software
+*    in a product, an acknowledgment in the product documentation would be
+*    appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+*    misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+**/
+
+#include "ThreadModule.h"
+
+namespace love
+{
+namespace thread
+{
+const char *ThreadModule::getName() const
+{
+	return "love.thread.sdl";
+}
+
+LuaThread *ThreadModule::newThread(const std::string &name, love::Data *data)
+{
+	LuaThread *lt = new LuaThread(name, data);
+	return lt;
+}
+
+Channel *ThreadModule::newChannel()
+{
+	return new Channel();
+}
+
+Channel *ThreadModule::getChannel(const std::string &name)
+{
+	return Channel::getChannel(name);
+}
+} // thread
+} // love

+ 52 - 0
src/modules/thread/ThreadModule.h

@@ -0,0 +1,52 @@
+/**
+* Copyright (c) 2006-2012 LOVE Development Team
+*
+* This software is provided 'as-is', without any express or implied
+* warranty.  In no event will the authors be held liable for any damages
+* arising from the use of this software.
+*
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+*
+* 1. The origin of this software must not be misrepresented; you must not
+*    claim that you wrote the original software. If you use this software
+*    in a product, an acknowledgment in the product documentation would be
+*    appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+*    misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+**/
+
+#ifndef LOVE_THREAD_THREADMODULE_H
+#define LOVE_THREAD_THREADMODULE_H
+
+// STL
+#include <string>
+
+// LOVE
+#include <common/Data.h>
+#include <common/Module.h>
+#include <thread/Thread.h>
+#include <thread/Channel.h>
+#include <thread/LuaThread.h>
+#include <thread/threads.h>
+
+namespace love
+{
+namespace thread
+{
+class ThreadModule : public love::Module
+{
+public:
+	virtual ~ThreadModule() {}
+	LuaThread *newThread(const std::string &name, love::Data *data);
+	Channel *newChannel();
+	Channel *getChannel(const std::string &name);
+
+	const char *getName() const;
+}; // ThreadModule
+} // thread
+} // love
+
+#endif // LOVE_THREAD_THREADMODULE_H

+ 0 - 192
src/modules/thread/posix/threads.cpp

@@ -1,192 +0,0 @@
-/**
- * Copyright (c) 2006-2013 LOVE Development Team
- *
- * This software is provided 'as-is', without any express or implied
- * warranty.  In no event will the authors be held liable for any damages
- * arising from the use of this software.
- *
- * Permission is granted to anyone to use this software for any purpose,
- * including commercial applications, and to alter it and redistribute it
- * freely, subject to the following restrictions:
- *
- * 1. The origin of this software must not be misrepresented; you must not
- *    claim that you wrote the original software. If you use this software
- *    in a product, an acknowledgment in the product documentation would be
- *    appreciated but is not required.
- * 2. Altered source versions must be plainly marked as such, and must not be
- *    misrepresented as being the original software.
- * 3. This notice may not be removed or altered from any source distribution.
- **/
-
-#include "threads.h"
-#ifdef LOVE_MACOSX
-#include "common/delay.h" // for Mac OS X's fake sem_timedwait
-#endif
-
-namespace love
-{
-namespace thread
-{
-
-Mutex::Mutex()
-{
-	pthread_mutex_init(&mutex, NULL);
-}
-
-Mutex::~Mutex()
-{
-	pthread_mutex_destroy(&mutex);
-}
-
-void Mutex::lock()
-{
-	pthread_mutex_lock(&mutex);
-}
-
-void Mutex::unlock()
-{
-	pthread_mutex_unlock(&mutex);
-}
-
-void *ThreadBase::thread_runner(void *param)
-{
-	ThreadBase *thread = (ThreadBase *)param;
-	thread->main();
-	return NULL;
-}
-
-ThreadBase::ThreadBase()
-	: running(false)
-{
-	pthread_t thread;
-}
-
-ThreadBase::~ThreadBase()
-{
-	if (running)
-	{
-		wait();
-	}
-}
-
-bool ThreadBase::start()
-{
-	if (pthread_create(&thread, NULL, thread_runner, this))
-		return false;
-	return (running = true);
-}
-
-void ThreadBase::wait()
-{
-	pthread_join(thread, NULL);
-	running = false;
-}
-
-void ThreadBase::kill()
-{
-	pthread_kill(thread, 9);
-	running = false;
-}
-
-unsigned int ThreadBase::threadId()
-{
-	return (unsigned int)((size_t)pthread_self());
-}
-
-Semaphore::Semaphore(unsigned int initial_value)
-{
-	sem_init(&sem, 0, initial_value);
-}
-
-Semaphore::~Semaphore()
-{
-	sem_destroy(&sem);
-}
-
-unsigned int Semaphore::value()
-{
-	int val = 0;
-	if (sem_getvalue(&sem, &val))
-		return 0;
-	else
-		return val;
-}
-
-void Semaphore::post()
-{
-	sem_post(&sem);
-}
-
-bool Semaphore::wait(int timeout)
-{
-	if (timeout < 0)
-		return !sem_wait(&sem);
-	else if (timeout == 0)
-		return !sem_trywait(&sem);
-	else
-	{
-#ifdef LOVE_MACOSX
-		// OS X lacks sem_timedwait, so we fake it with a busy loop
-		time_t timer = time(NULL)*1000 + timeout;
-		int retval = 0;
-		do
-		{
-			retval = sem_trywait(&sem);
-			if (retval == 0) break;
-			delay(1);
-		}
-		while (time(NULL)*1000 < timer);
-		return !retval;
-#else
-		struct timespec ts;
-		ts.tv_sec = timeout/1000;
-		ts.tv_nsec = (timeout % 1000) * 1000000;
-		return !sem_timedwait(&sem, &ts);
-#endif
-	}
-}
-
-bool Semaphore::tryWait()
-{
-	return !sem_trywait(&sem);
-}
-
-Conditional::Conditional()
-{
-	pthread_cond_init(&cond, NULL);
-}
-
-Conditional::~Conditional()
-{
-	pthread_cond_destroy(&cond);
-}
-
-void Conditional::signal()
-{
-	pthread_cond_signal(&cond);
-}
-
-void Conditional::broadcast()
-{
-	pthread_cond_broadcast(&cond);
-}
-
-bool Conditional::wait(Mutex *mutex, int timeout)
-{
-	if (timeout < 0)
-		return !pthread_cond_wait(&cond, &mutex->mutex);
-	else
-	{
-		struct timespec ts;
-		int ret;
-
-		ts.tv_sec = timeout / 1000;
-		ts.tv_nsec = (timeout % 1000) * 1000000;
-
-		ret = pthread_cond_timedwait(&cond, &mutex->mutex, &ts);
-		return (ret == 0);
-	}
-}
-} // thread
-} // love
-

+ 0 - 107
src/modules/thread/posix/threads.h

@@ -1,107 +0,0 @@
-/**
- * Copyright (c) 2006-2013 LOVE Development Team
- *
- * This software is provided 'as-is', without any express or implied
- * warranty.  In no event will the authors be held liable for any damages
- * arising from the use of this software.
- *
- * Permission is granted to anyone to use this software for any purpose,
- * including commercial applications, and to alter it and redistribute it
- * freely, subject to the following restrictions:
- *
- * 1. The origin of this software must not be misrepresented; you must not
- *    claim that you wrote the original software. If you use this software
- *    in a product, an acknowledgment in the product documentation would be
- *    appreciated but is not required.
- * 2. Altered source versions must be plainly marked as such, and must not be
- *    misrepresented as being the original software.
- * 3. This notice may not be removed or altered from any source distribution.
- **/
-
-#ifndef LOVE_THREAD_POSIX_THREADS_H
-#define LOVE_THREAD_POSIX_THREADS_H
-
-#include <pthread.h>
-#include <semaphore.h>
-#include <signal.h>
-
-namespace love
-{
-namespace thread
-{
-class Mutex
-{
-public:
-	Mutex();
-	~Mutex();
-
-	void lock();
-	void unlock();
-
-private:
-	pthread_mutex_t mutex;
-	Mutex(const Mutex &mutex) {}
-
-	friend class Conditional;
-};
-
-
-class ThreadBase
-{
-public:
-	ThreadBase();
-	virtual ~ThreadBase();
-
-	bool start();
-	void wait();
-	void kill();
-
-	static unsigned int threadId();
-
-protected:
-	virtual void main() = 0;
-
-private:
-	pthread_t thread;
-	ThreadBase(ThreadBase &thread) {}
-
-	static void *thread_runner(void *param);
-	bool running;
-};
-
-class Semaphore
-{
-public:
-	Semaphore(unsigned int initial_value);
-	~Semaphore();
-
-	unsigned int value();
-	void post();
-	bool wait(int timeout = -1);
-	bool tryWait();
-
-private:
-	Semaphore(const Semaphore &sem) {}
-	sem_t sem;
-};
-
-// Should conditional inherit from mutex?
-class Conditional
-{
-public:
-	Conditional();
-	~Conditional();
-
-	void signal();
-	void broadcast();
-	bool wait(Mutex *mutex, int timeout=-1);
-
-private:
-	pthread_cond_t cond;
-};
-
-} // thread
-} // love
-
-
-#endif // LOVE_THREAD_POSIX_THREADS_H

+ 92 - 0
src/modules/thread/sdl/Thread.cpp

@@ -0,0 +1,92 @@
+/**
+* Copyright (c) 2006-2012 LOVE Development Team
+*
+* This software is provided 'as-is', without any express or implied
+* warranty.  In no event will the authors be held liable for any damages
+* arising from the use of this software.
+*
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+*
+* 1. The origin of this software must not be misrepresented; you must not
+*    claim that you wrote the original software. If you use this software
+*    in a product, an acknowledgment in the product documentation would be
+*    appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+*    misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+**/
+
+#include "Thread.h"
+
+namespace love
+{
+namespace thread
+{
+namespace sdl
+{
+Thread::Thread(Threadable *t)
+	: t(t)
+	, running(false)
+	, thread(0)
+{
+}
+
+Thread::~Thread()
+{
+	if (!running) // Clean up handle
+		wait();
+	/*
+	if (running)
+		wait();
+	FIXME: Needed for proper thread cleanup
+	*/
+}
+
+bool Thread::start()
+{
+	Lock l(mutex);
+	if (running)
+		return false;
+	if (thread) // Clean old handle up
+		SDL_WaitThread(thread, 0);
+	thread = SDL_CreateThread(thread_runner, this);
+	running = (thread != 0);
+	return running;
+}
+
+void Thread::wait()
+{
+	mutex.lock();
+	if (!thread)
+		return;
+	mutex.unlock();
+	SDL_WaitThread(thread, 0);
+	Lock l(mutex);
+	running = false;
+	thread = 0;
+}
+
+void Thread::kill()
+{
+	Lock l(mutex);
+	if (!running)
+		return;
+	SDL_KillThread(thread);
+	SDL_WaitThread(thread, 0);
+	running = false;
+	thread = 0;
+}
+
+int Thread::thread_runner(void *data)
+{
+	Thread *self = (Thread *) data; // some compilers don't like 'this'
+	self->t->threadFunction();
+	Lock l(self->mutex);
+	self->running = false;
+	return 0;
+}
+} // sdl
+} // thread
+} // love

+ 57 - 0
src/modules/thread/sdl/Thread.h

@@ -0,0 +1,57 @@
+/**
+* Copyright (c) 2006-2012 LOVE Development Team
+*
+* This software is provided 'as-is', without any express or implied
+* warranty.  In no event will the authors be held liable for any damages
+* arising from the use of this software.
+*
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+*
+* 1. The origin of this software must not be misrepresented; you must not
+*    claim that you wrote the original software. If you use this software
+*    in a product, an acknowledgment in the product documentation would be
+*    appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+*    misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+**/
+
+#ifndef LOVE_THREAD_SDL_THREAD_H
+#define LOVE_THREAD_SDL_THREAD_H
+
+// LOVE
+#include <thread/Thread.h>
+#include "threads.h"
+
+// SDL
+#include <SDL_thread.h>
+
+namespace love
+{
+namespace thread
+{
+namespace sdl
+{
+class Thread : public thread::Thread
+{
+private:
+	Threadable *t;
+	bool running;
+	SDL_Thread *thread;
+	static int thread_runner(void *data);
+	Mutex mutex;
+
+public:
+	Thread(Threadable *t);
+	~Thread();
+	bool start();
+	void kill();
+	void wait();
+}; // Thread
+} // sdl
+} // thread
+} // love
+
+#endif // LOVE_THREAD_SDL_THREAD_H

+ 25 - 86
src/modules/thread/sdl/threads.cpp

@@ -19,12 +19,14 @@
  **/
 
 #include "threads.h"
+#include "Thread.h"
 
 namespace love
 {
 namespace thread
 {
-
+namespace sdl
+{
 Mutex::Mutex()
 {
 	mutex = SDL_CreateMutex();
@@ -45,90 +47,6 @@ void Mutex::unlock()
 	SDL_mutexV(mutex);
 }
 
-int ThreadBase::thread_runner(void *param)
-{
-	ThreadBase *thread = (ThreadBase *)param;
-	thread->main();
-	return 0;
-}
-
-ThreadBase::ThreadBase()
-	: running(false)
-{
-}
-
-ThreadBase::~ThreadBase()
-{
-	if (running)
-	{
-		wait();
-	}
-}
-
-bool ThreadBase::start()
-{
-	thread = SDL_CreateThread(thread_runner, this);
-	if (thread == NULL)
-		return false;
-	else
-		return (running = true);
-}
-
-void ThreadBase::wait()
-{
-	SDL_WaitThread(thread, NULL);
-	running = false;
-}
-
-void ThreadBase::kill()
-{
-	SDL_KillThread(thread);
-	running = false;
-}
-
-unsigned int ThreadBase::threadId()
-{
-	return (unsigned int)SDL_ThreadID();
-}
-
-Semaphore::Semaphore(unsigned int initial_value)
-{
-	semaphore = SDL_CreateSemaphore(initial_value);
-}
-
-Semaphore::~Semaphore()
-{
-	SDL_DestroySemaphore(semaphore);
-}
-
-unsigned int Semaphore::value()
-{
-	return SDL_SemValue(semaphore);
-}
-
-void Semaphore::post()
-{
-	SDL_SemPost(semaphore);
-}
-
-bool Semaphore::wait(int timeout)
-{
-	if (timeout < 0)
-		return SDL_SemWait(semaphore) ? false : true;
-	else if (timeout == 0)
-		return SDL_SemTryWait(semaphore) ? false : true;
-	else
-	{
-		int ret = SDL_SemWaitTimeout(semaphore, timeout);
-		return (ret == 0);
-	}
-}
-
-bool Semaphore::tryWait()
-{
-	return SDL_SemTryWait(semaphore) ? false : true;
-}
-
 Conditional::Conditional()
 {
 	cond = SDL_CreateCond();
@@ -149,13 +67,34 @@ void Conditional::broadcast()
 	SDL_CondBroadcast(cond);
 }
 
-bool Conditional::wait(Mutex *mutex, int timeout)
+bool Conditional::wait(thread::Mutex *_mutex, int timeout)
 {
+	// Yes, I realise this can be dangerous,
+	// however, you're asking for it if you're
+	// mixing thread implementations.
+	Mutex *mutex = (Mutex *) _mutex;
 	if (timeout < 0)
 		return !SDL_CondWait(cond, mutex->mutex);
 	else
 		return (SDL_CondWaitTimeout(cond, mutex->mutex, timeout) == 0);
 }
 
+} // sdl
+
+thread::Mutex *newMutex()
+{
+	return new sdl::Mutex();
+}
+
+thread::Conditional *newConditional()
+{
+	return new sdl::Conditional();
+}
+
+thread::Thread *newThread(Threadable *t)
+{
+	return new sdl::Thread(t);
+}
+
 } // thread
 } // love

+ 14 - 50
src/modules/thread/sdl/threads.h

@@ -21,15 +21,20 @@
 #ifndef LOVE_THREAD_SDL_THREADS_H
 #define LOVE_THREAD_SDL_THREADS_H
 
-#include "SDL.h"
-#include "common/config.h"
+#include <common/config.h>
+#include <thread/threads.h>
+
+#include <SDL_thread.h>
 
 namespace love
 {
 namespace thread
 {
+namespace sdl
+{
+class Conditional;
 
-class Mutex
+class Mutex : public thread::Mutex
 {
 public:
 	Mutex();
@@ -37,56 +42,15 @@ public:
 
 	void lock();
 	void unlock();
+
 private:
 	SDL_mutex *mutex;
-	Mutex(const Mutex &/* mutex*/) {}
+	Mutex(const Mutex&/* mutex*/) {}
 
 	friend class Conditional;
 };
 
-
-
-class ThreadBase
-{
-public:
-	ThreadBase();
-	virtual ~ThreadBase();
-
-	bool start();
-	void wait();
-	void kill(); // FIXME: not supported by SDL (SDL's kill is probably cancel)?
-
-	static unsigned int threadId();
-
-protected:
-	virtual void main() = 0;
-
-private:
-	SDL_Thread *thread;
-	ThreadBase(ThreadBase &/* thread*/) {}
-	bool running;
-
-	static int thread_runner(void *param);
-};
-
-class Semaphore
-{
-public:
-	Semaphore(unsigned int initial_value);
-	~Semaphore();
-
-	unsigned int value();
-	void post();
-	bool wait(int timeout = -1);
-	bool tryWait();
-
-private:
-	Semaphore(const Semaphore &/* sem*/) {}
-	SDL_sem *semaphore;
-};
-
-// Should conditional inherit from mutex?
-class Conditional
+class Conditional : public thread::Conditional
 {
 public:
 	Conditional();
@@ -94,14 +58,14 @@ public:
 
 	void signal();
 	void broadcast();
-	bool wait(Mutex *mutex, int timeout=-1);
+	bool wait(thread::Mutex *mutex, int timeout=-1);
 
 private:
 	SDL_cond *cond;
 };
 
+} // sdl
 } // thread
 } // love
 
-
-#endif // LOVE_THREAD_SDL_THREADS_H
+#endif /* LOVE_THREAD_SDL_THREADS_H */

+ 39 - 16
src/modules/thread/threads.cpp

@@ -20,28 +20,51 @@
 
 #include "threads.h"
 
-#if LOVE_THREADS == LOVE_THREADS_POSIX
-#  include "posix/threads.cpp"
-#elif LOVE_THREADS == LOVE_THREADS_WIN32
-#  include "win32/threads.cpp"
-#elif LOVE_THREADS == LOVE_THREADS_SDL
-#  include "sdl/threads.cpp"
-#endif
-
 namespace love
 {
 namespace thread
 {
 
-const char *threadAPI()
+Lock::Lock(Mutex *m)
+	: mutex(m)
+{
+	mutex->lock();
+}
+
+Lock::Lock(Mutex &m)
+	: mutex(&m)
+{
+	mutex->lock();
+}
+
+Lock::~Lock()
+{
+	mutex->unlock();
+}
+
+Threadable::Threadable()
+{
+	owner = newThread(this);
+}
+
+Threadable::~Threadable()
+{
+	delete owner;
+}
+
+bool Threadable::start()
+{
+	return owner->start();
+}
+
+void Threadable::wait()
+{
+	owner->wait();
+}
+
+void Threadable::kill()
 {
-#if LOVE_THREADS == LOVE_THREADS_POSIX
-	return "posix";
-#elif LOVE_THREADS == LOVE_THREADS_WIN32
-	return "win32";
-#elif LOVE_THREADS == LOVE_THREADS_SDL
-	return "sdl";
-#endif
+	owner->kill();
 }
 
 } // thread

+ 43 - 45
src/modules/thread/threads.h

@@ -21,66 +21,64 @@
 #ifndef LOVE_THREAD_THREADS_H
 #define LOVE_THREAD_THREADS_H
 
-#include "common/config.h"
-
-#define LOVE_THREADS_SDL	0
-#define LOVE_THREADS_WIN32	1
-#define LOVE_THREADS_POSIX	2
-
-// Choose correct threads API.
-// Headless love uses either windows threads or posix threads.
-// Headed (standard) love uses SDL threads.
-#ifdef LOVE_HEADLESS
-#  ifdef WIN32
-#    define LOVE_THREADS	LOVE_THREADS_WIN32
-#  else
-#    define LOVE_THREADS	LOVE_THREADS_POSIX
-#  endif
-#else
-#  define LOVE_THREADS	LOVE_THREADS_SDL
-#endif
-
-
-// include the correct header
-#if LOVE_THREADS == LOVE_THREADS_POSIX
-#  include "posix/threads.h"
-#elif LOVE_THREADS == LOVE_THREADS_WIN32
-#  include "win32/threads.h"
-#elif LOVE_THREADS == LOVE_THREADS_SDL
-#  include "sdl/threads.h"
-#endif
-
+#include <common/config.h>
+#include "Thread.h"
 
 namespace love
 {
 namespace thread
 {
 
-const char *threadAPI();
+class Mutex
+{
+public:
+	virtual ~Mutex() {}
+
+	virtual void lock() = 0;
+	virtual void unlock() = 0;
+};
+
+class Conditional
+{
+public:
+	virtual ~Conditional() {}
+
+	virtual void signal() = 0;
+	virtual void broadcast() = 0;
+	virtual bool wait(Mutex *mutex, int timeout=-1) = 0;
+};
 
 class Lock
 {
 public:
-	Lock(Mutex *m): mutex(m)
-	{
-		mutex->lock();
-	}
-
-	Lock(Mutex &m): mutex(&m)
-	{
-		mutex->lock();
-	}
-
-	~Lock()
-	{
-		mutex->unlock();
-	}
+	Lock(Mutex *m);
+	Lock(Mutex &m);
+	~Lock();
+
 private:
 	Mutex *mutex;
+};
 
-	Lock(Lock &/* lock*/) {}
+class Threadable
+{
+public:
+	Threadable();
+	virtual ~Threadable();
+
+	virtual void threadFunction() = 0;
+
+	bool start();
+	void wait();
+	void kill();
+
+protected:
+	Thread *owner;
 };
 
+Mutex *newMutex();
+Conditional *newConditional();
+Thread *newThread(Threadable *t);
+
 } // thread
 } // love
 

+ 0 - 211
src/modules/thread/win32/threads.cpp

@@ -1,211 +0,0 @@
-/**
- * Copyright (c) 2006-2013 LOVE Development Team
- *
- * This software is provided 'as-is', without any express or implied
- * warranty.  In no event will the authors be held liable for any damages
- * arising from the use of this software.
- *
- * Permission is granted to anyone to use this software for any purpose,
- * including commercial applications, and to alter it and redistribute it
- * freely, subject to the following restrictions:
- *
- * 1. The origin of this software must not be misrepresented; you must not
- *    claim that you wrote the original software. If you use this software
- *    in a product, an acknowledgment in the product documentation would be
- *    appreciated but is not required.
- * 2. Altered source versions must be plainly marked as such, and must not be
- *    misrepresented as being the original software.
- * 3. This notice may not be removed or altered from any source distribution.
- **/
-
-#include "threads.h"
-
-namespace love
-{
-namespace thread
-{
-
-Mutex::Mutex()
-{
-	InitializeCriticalSection(&mutex);
-}
-
-Mutex::~Mutex()
-{
-	DeleteCriticalSection(&mutex);
-}
-
-void Mutex::lock()
-{
-	EnterCriticalSection(&mutex);
-}
-
-void Mutex::unlock()
-{
-	LeaveCriticalSection(&mutex);
-}
-
-int ThreadBase::thread_runner(void *param)
-{
-	ThreadBase *thread = (ThreadBase *)param;
-	thread->main();
-	return 0;
-}
-
-ThreadBase::ThreadBase()
-	: running(false)
-{
-}
-
-ThreadBase::~ThreadBase()
-{
-	if (running)
-		wait();
-}
-
-bool ThreadBase::start()
-{
-	thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) thread_runner, this, 0, NULL);
-	if (thread == NULL)
-		return false;
-	else
-		return (running = true);
-}
-
-void ThreadBase::wait()
-{
-	WaitForSingleObject(thread, INFINITE);
-	CloseHandle(thread);
-	running = false;
-}
-
-void ThreadBase::kill()
-{
-	TerminateThread(thread, FALSE);
-	running = false;
-}
-
-unsigned int ThreadBase::threadId()
-{
-	return (unsigned int)GetCurrentThreadId();
-}
-
-Semaphore::Semaphore(unsigned int initial_value)
-	: count(initial_value)
-{
-	semaphore = CreateSemaphore(NULL, initial_value, UINT_MAX, NULL);
-}
-
-Semaphore::~Semaphore()
-{
-	CloseHandle(semaphore);
-}
-
-unsigned int Semaphore::value()
-{
-	return count;
-}
-
-void Semaphore::post()
-{
-	InterlockedIncrement(&count);
-	if (ReleaseSemaphore(semaphore, 1, NULL) == FALSE)
-		InterlockedDecrement(&count);
-}
-
-bool Semaphore::wait(int timeout)
-{
-	int result;
-
-	result = WaitForSingleObject(semaphore, timeout < 0 ? INFINITE : timeout);
-	if (result == WAIT_OBJECT_0)
-	{
-		InterlockedDecrement(&count);
-		return true;
-	}
-	else
-		return false;
-}
-
-bool Semaphore::tryWait()
-{
-	return wait(0);
-}
-
-
-// Conditional variable implementation based on semaphores.
-// Vista+ builds should probably use CONDITIONAL_VARIABLE.
-//
-// based on http://www.cs.wustl.edu/~schmidt/win32-cv-2.html and ACE
-
-
-Conditional::Conditional()
-	: waiting(0), signals(0)
-{
-}
-
-Conditional::~Conditional()
-{
-}
-
-void Conditional::signal()
-{
-	mutex.lock();
-	if (waiting > signals)
-	{
-		signals++;
-		sem.post();
-		mutex.unlock();
-		done.wait();
-	}
-	else
-	{
-		mutex.unlock();
-	}
-}
-
-void Conditional::broadcast()
-{
-	mutex.lock();
-	if (waiting > signals)
-	{
-		int num = waiting - signals;
-		signals = waiting;
-		for (int i = 0; i < num; i++)
-			sem.post();
-		mutex.unlock();
-		for (int i = 0; i < num; i++)
-			done.wait();
-	}
-	else
-	{
-		mutex.unlock();
-	}
-}
-
-bool Conditional::wait(Mutex *cmutex, int timeout)
-{
-	mutex.lock();
-	waiting++;
-	mutex.unlock();
-
-	cmutex->unlock();
-	bool ret = sem.wait(timeout);
-
-	mutex.lock();
-	if (signals > 0)
-	{
-		if (!ret)
-			sem.wait();
-		done.post();
-		signals--;
-	}
-	waiting--;
-	mutex.unlock();
-	cmutex->lock();
-
-	return true;
-}
-
-} // thread
-} // love

+ 0 - 107
src/modules/thread/win32/threads.h

@@ -1,107 +0,0 @@
-/**
- * Copyright (c) 2006-2013 LOVE Development Team
- *
- * This software is provided 'as-is', without any express or implied
- * warranty.  In no event will the authors be held liable for any damages
- * arising from the use of this software.
- *
- * Permission is granted to anyone to use this software for any purpose,
- * including commercial applications, and to alter it and redistribute it
- * freely, subject to the following restrictions:
- *
- * 1. The origin of this software must not be misrepresented; you must not
- *    claim that you wrote the original software. If you use this software
- *    in a product, an acknowledgment in the product documentation would be
- *    appreciated but is not required.
- * 2. Altered source versions must be plainly marked as such, and must not be
- *    misrepresented as being the original software.
- * 3. This notice may not be removed or altered from any source distribution.
- **/
-
-#ifndef LOVE_THREAD_WIN32_THREADS_H
-#define LOVE_THREAD_WIN32_THREADS_H
-
-#include <windows.h>
-#include <limits.h>
-
-namespace love
-{
-namespace thread
-{
-
-class Mutex
-{
-public:
-	Mutex();
-	~Mutex();
-
-	void lock();
-	void unlock();
-private:
-	CRITICAL_SECTION mutex;
-	Mutex(const Mutex &mutex) {}
-};
-
-class ThreadBase
-{
-public:
-	ThreadBase();
-	virtual ~ThreadBase();
-
-	bool start();
-	void wait();
-	void kill();
-
-	static unsigned int threadId();
-
-protected:
-
-	virtual void main() = 0;
-
-private:
-	HANDLE thread;
-	ThreadBase(ThreadBase &thread) {}
-	bool running;
-
-	static int WINAPI thread_runner(void *param);
-};
-
-
-class Semaphore
-{
-public:
-	Semaphore(unsigned int initial_value = 0);
-	~Semaphore();
-
-	unsigned int value();
-	void post();
-	bool wait(int timeout = -1);
-	bool tryWait();
-private:
-	Semaphore(const Semaphore &sem) {}
-	HANDLE semaphore;
-	unsigned int count;
-};
-
-
-// Should conditional inherit from mutex?
-class Conditional
-{
-public:
-	Conditional();
-	~Conditional();
-
-	void signal();
-	void broadcast();
-	bool wait(Mutex *cmutex, int timeout=-1);
-private:
-	Mutex mutex;
-	int waiting;
-	int signals;
-	Semaphore sem;
-	Semaphore done;
-};
-} // thread
-} // love
-
-#endif /* LOVE_THREAD_WIN32_THREADS_H */

+ 131 - 0
src/modules/thread/wrap_Channel.cpp

@@ -0,0 +1,131 @@
+/**
+* Copyright (c) 2006-2010 LOVE Development Team
+*
+* This software is provided 'as-is', without any express or implied
+* warranty.  In no event will the authors be held liable for any damages
+* arising from the use of this software.
+*
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+*
+* 1. The origin of this software must not be misrepresented; you must not
+*    claim that you wrote the original software. If you use this software
+*    in a product, an acknowledgment in the product documentation would be
+*    appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+*    misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+**/
+
+#include "wrap_Channel.h"
+
+namespace love
+{
+namespace thread
+{
+void retainVariant(Channel *c, Variant *v)
+{
+	c->lockMutex();
+	v->retain();
+	c->unlockMutex();
+}
+
+void releaseVariant(Channel *c, Variant *v)
+{
+	c->lockMutex();
+	v->release();
+	c->unlockMutex();
+}
+
+Channel *luax_checkchannel(lua_State *L, int idx)
+{
+	return luax_checktype<Channel>(L, idx, "Channel", THREAD_CHANNEL_T);
+}
+
+int w_Channel_push(lua_State *L)
+{
+	Channel *c = luax_checkchannel(L, 1);
+	Variant *var = Variant::fromLua(L, 2);
+	c->push(var);
+	releaseVariant(c, var);
+	return 0;
+}
+
+int w_Channel_supply(lua_State *L)
+{
+	Channel *c = luax_checkchannel(L, 1);
+	Variant *var = Variant::fromLua(L, 2);
+	c->supply(var);
+	releaseVariant(c, var);
+	return 0;
+}
+
+int w_Channel_pop(lua_State *L)
+{
+	Channel *c = luax_checkchannel(L, 1);
+	Variant *var = c->pop();
+	if (var)
+	{
+		var->toLua(L);
+		releaseVariant(c, var);
+	}
+	else
+		lua_pushnil(L);
+	return 1;
+}
+
+int w_Channel_demand(lua_State *L)
+{
+	Channel *c = luax_checkchannel(L, 1);
+	Variant *var = c->demand();
+	var->toLua(L);
+	releaseVariant(c, var);
+	return 1;
+}
+
+int w_Channel_peek(lua_State *L)
+{
+	Channel *c = luax_checkchannel(L, 1);
+	Variant *var = c->peek();
+	if (var)
+	{
+		var->toLua(L);
+		releaseVariant(c, var);
+	}
+	else
+		lua_pushnil(L);
+	return 1;
+}
+
+int w_Channel_count(lua_State *L)
+{
+	Channel *c = luax_checkchannel(L, 1);
+	lua_pushnumber(L, c->count());
+	return 1;
+}
+
+int w_Channel_clear(lua_State *L)
+{
+	Channel *c = luax_checkchannel(L, 1);
+	c->clear();
+	return 0;
+}
+
+static const luaL_Reg type_functions[] = {
+	{ "push", w_Channel_push },
+	{ "supply", w_Channel_supply },
+	{ "pop", w_Channel_pop },
+	{ "demand", w_Channel_demand },
+	{ "peek", w_Channel_peek },
+	{ "count", w_Channel_count },
+	{ "clear", w_Channel_clear },
+	{ 0, 0 }
+};
+
+extern "C" int luaopen_channel(lua_State *L)
+{
+	return luax_register_type(L, "Channel", type_functions);
+}
+}
+}

+ 44 - 0
src/modules/thread/wrap_Channel.h

@@ -0,0 +1,44 @@
+/**
+* Copyright (c) 2006-2012 LOVE Development Team
+*
+* This software is provided 'as-is', without any express or implied
+* warranty.  In no event will the authors be held liable for any damages
+* arising from the use of this software.
+*
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+*
+* 1. The origin of this software must not be misrepresented; you must not
+*    claim that you wrote the original software. If you use this software
+*    in a product, an acknowledgment in the product documentation would be
+*    appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+*    misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+**/
+
+#ifndef LOVE_THREAD_WRAP_CHANNEL_H
+#define LOVE_THREAD_WRAP_CHANNEL_H
+
+// LOVE
+#include "Channel.h"
+
+namespace love
+{
+namespace thread
+{
+Channel *luax_checkchannel(lua_State *L, int idx);
+int w_Channel_push(lua_State *L);
+int w_Channel_supply(lua_State *L);
+int w_Channel_pop(lua_State *L);
+int w_Channel_demand(lua_State *L);
+int w_Channel_peek(lua_State *L);
+int w_Channel_count(lua_State *L);
+int w_Channel_clear(lua_State *L);
+
+extern "C" int luaopen_channel(lua_State *L);
+} // thread
+} // love
+
+#endif // LOVE_THREAD_WRAP_CHANNEL_H

+ 71 - 0
src/modules/thread/wrap_LuaThread.cpp

@@ -0,0 +1,71 @@
+/**
+ * Copyright (c) 2006-2010 LOVE Development Team
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ **/
+
+#include "wrap_LuaThread.h"
+
+namespace love
+{
+namespace thread
+{
+
+LuaThread *luax_checkthread(lua_State *L, int idx)
+{
+	return luax_checktype<LuaThread>(L, idx, "Thread", THREAD_THREAD_T);
+}
+
+int w_Thread_start(lua_State *L)
+{
+	LuaThread *t = luax_checkthread(L, 1);
+	luax_pushboolean(L, t->start());
+	return 1;
+}
+
+int w_Thread_wait(lua_State *L)
+{
+	LuaThread *t = luax_checkthread(L, 1);
+	t->wait();
+	return 0;
+}
+
+int w_Thread_getError(lua_State *L)
+{
+	LuaThread *t = luax_checkthread(L, 1);
+	std::string err = t->getError();
+	if (err.length() == 0)
+		lua_pushnil(L);
+	else
+		luax_pushstring(L, err);
+	return 1;
+}
+
+static const luaL_Reg type_functions[] = {
+	{ "start", w_Thread_start },
+	{ "wait", w_Thread_wait },
+	{ "getError", w_Thread_getError },
+	{ 0, 0 }
+};
+
+extern "C" int luaopen_thread(lua_State *L)
+{
+	return luax_register_type(L, "Thread", type_functions);
+}
+
+} // thread
+} // love

+ 7 - 19
src/modules/thread/wrap_Thread.h → src/modules/thread/wrap_LuaThread.h

@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2006-2013 LOVE Development Team
+ * Copyright (c) 2006-2012 LOVE Development Team
  *
  * This software is provided 'as-is', without any express or implied
  * warranty.  In no event will the authors be held liable for any damages
@@ -18,37 +18,25 @@
  * 3. This notice may not be removed or altered from any source distribution.
  **/
 
-#ifndef LOVE_THREAD_SDL_WRAP_THREAD_H
-#define LOVE_THREAD_SDL_WRAP_THREAD_H
+#ifndef LOVE_THREAD_WRAP_LUATHREAD_H
+#define LOVE_THREAD_WRAP_LUATHREAD_H
 
 // LOVE
-#include "common/config.h"
-#include "Thread.h"
+#include "ThreadModule.h"
 
 namespace love
 {
 namespace thread
 {
 
-Thread *luax_checkthread(lua_State *L, int idx);
+LuaThread *luax_checkthread(lua_State *L, int idx);
 int w_Thread_start(lua_State *L);
 int w_Thread_wait(lua_State *L);
-int w_Thread_getName(lua_State *L);
-int w_Thread_get(lua_State *L);
-int w_Thread_getKeys(lua_State *L);
-int w_Thread_demand(lua_State *L);
-int w_Thread_peek(lua_State *L);
-int w_Thread_set(lua_State *L);
+int w_Thread_getError(lua_State *L);
 
 extern "C" int luaopen_thread(lua_State *L);
 
-int w_newThread(lua_State *L);
-int w_getThreads(lua_State *L);
-int w_getThread(lua_State *L);
-
-extern "C" LOVE_EXPORT int luaopen_love_thread(lua_State *L);
-
 } // thread
 } // love
 
-#endif // LOVE_THREAD_SDL_WRAP_THREAD_H
+#endif // LOVE_THREAD_WRAP_LUATHREAD_H

+ 0 - 290
src/modules/thread/wrap_Thread.cpp

@@ -1,290 +0,0 @@
-/**
- * Copyright (c) 2006-2010 LOVE Development Team
- *
- * This software is provided 'as-is', without any express or implied
- * warranty.  In no event will the authors be held liable for any damages
- * arising from the use of this software.
- *
- * Permission is granted to anyone to use this software for any purpose,
- * including commercial applications, and to alter it and redistribute it
- * freely, subject to the following restrictions:
- *
- * 1. The origin of this software must not be misrepresented; you must not
- *    claim that you wrote the original software. If you use this software
- *    in a product, an acknowledgment in the product documentation would be
- *    appreciated but is not required.
- * 2. Altered source versions must be plainly marked as such, and must not be
- *    misrepresented as being the original software.
- * 3. This notice may not be removed or altered from any source distribution.
- **/
-
-#include "wrap_Thread.h"
-
-namespace love
-{
-namespace thread
-{
-
-Thread *luax_checkthread(lua_State *L, int idx)
-{
-	return luax_checktype<Thread>(L, idx, "Thread", THREAD_THREAD_T);
-}
-
-int w_Thread_start(lua_State *L)
-{
-	Thread *t = luax_checkthread(L, 1);
-	t->start();
-	return 0;
-}
-
-int w_Thread_wait(lua_State *L)
-{
-	Thread *t = luax_checkthread(L, 1);
-	t->wait();
-	return 0;
-}
-
-int w_Thread_getName(lua_State *L)
-{
-	Thread *t = luax_checkthread(L, 1);
-	// allow names containing \0
-	luax_pushstring(L, t->getName());
-	return 1;
-}
-
-
-int w_Thread_get(lua_State *L)
-{
-	Thread *t = luax_checkthread(L, 1);
-	std::string name = luax_checkstring(L, 2);
-	t->lock();
-	Variant *v = t->get(name);
-	t->clear(name);
-	t->unlock();
-	if (!v)
-	{
-		lua_pushnil(L);
-		return 1;
-	}
-	v->toLua(L);
-	t->lock();
-	v->release();
-	t->unlock();
-	return 1;
-}
-
-int w_Thread_getKeys(lua_State *L)
-{
-	Thread *t = luax_checkthread(L, 1);
-	t->lock();
-	std::vector<std::string> keys = t->getKeys();
-	t->unlock();
-	lua_createtable(L, keys.size(), 0);
-	int i = 1;
-	for (std::vector<std::string>::iterator it = keys.begin(); it != keys.end(); it++)
-	{
-		lua_pushnumber(L, i++);
-		luax_pushstring(L, *it);
-		lua_settable(L, -3);
-	}
-	return 1;
-}
-
-int w_Thread_demand(lua_State *L)
-{
-	Thread *t = luax_checkthread(L, 1);
-	std::string name = luax_checkstring(L, 2);
-	t->lock();
-	Variant *v = t->demand(name);
-	t->clear(name);
-	t->unlock();
-	if (!v)
-	{
-		lua_pushnil(L);
-		return 1;
-	}
-	v->toLua(L);
-	t->lock();
-	v->release();
-	t->unlock();
-	return 1;
-}
-
-int w_Thread_peek(lua_State *L)
-{
-	Thread *t = luax_checkthread(L, 1);
-	std::string name = luax_checkstring(L, 2);
-	t->lock();
-	Variant *v = t->get(name);
-	t->unlock();
-	if (!v)
-	{
-		lua_pushnil(L);
-		return 1;
-	}
-	v->toLua(L);
-	t->lock();
-	v->release();
-	t->unlock();
-	return 1;
-}
-
-
-int w_Thread_set(lua_State *L)
-{
-	Thread *t = luax_checkthread(L, 1);
-	std::string name = luax_checkstring(L, 2);
-	Variant *v = Variant::fromLua(L, 3);
-	if (!v)
-		return luaL_error(L, "Expected boolean, number, string or userdata");
-	t->set(name, v);
-	t->lock();
-	v->release();
-	t->unlock();
-	return 0;
-}
-
-static const luaL_Reg type_functions[] =
-{
-	{ "start", w_Thread_start },
-	{ "wait", w_Thread_wait },
-	{ "getName", w_Thread_getName },
-	{ "get", w_Thread_get },
-	{ "getKeys", w_Thread_getKeys },
-	{ "demand", w_Thread_demand },
-	{ "peek", w_Thread_peek },
-	{ "set", w_Thread_set },
-	{ 0, 0 }
-};
-
-extern "C" int luaopen_thread(lua_State *L)
-{
-	return luax_register_type(L, "Thread", type_functions);
-}
-
-static ThreadModule *instance;
-
-int w_newThread(lua_State *L)
-{
-	std::string name = luax_checkstring(L, 1);
-	love::Data *data;
-	if (lua_isstring(L, 2))
-		luax_convobj(L, 2, "filesystem", "newFile");
-	if (luax_istype(L, 2, FILESYSTEM_FILE_T))
-	{
-		try
-		{
-			data = luax_checktype<love::filesystem::File>(L, 2, "File", FILESYSTEM_FILE_T)->read();
-		}
-		catch(love::Exception &e)
-		{
-			return luaL_error(L, e.what());
-		}
-	}
-	else
-	{
-		data = luax_checktype<love::Data>(L, 2, "Data", DATA_T);
-		data->retain();
-	}
-	Thread *t = instance->newThread(name, data);
-	// do not worry, file->read() returns retained data
-	data->release();
-	if (!t)
-		return luaL_error(L, "A thread with that name already exists.");
-	luax_newtype(L, "Thread", THREAD_THREAD_T, (void *)t);
-	return 1;
-}
-
-int w_getThreads(lua_State *L)
-{
-	unsigned count = instance->getThreadCount();
-	Thread **list = new Thread*[count];
-	instance->getThreads(list);
-	lua_newtable(L);
-	for (unsigned int i = 0; i<count; i++)
-	{
-		// allow names containing \0
-		luax_pushstring(L, list[i]->getName());
-		luax_newtype(L, "Thread", THREAD_THREAD_T, (void *) list[i]);
-		list[i]->lock();
-		list[i]->retain();
-		list[i]->unlock();
-		lua_settable(L, -3);
-	}
-	delete[] list;
-	return 1;
-}
-
-int w_getThread(lua_State *L)
-{
-	if (lua_isnoneornil(L, 1))
-	{
-		lua_getglobal(L, "love");
-		lua_getfield(L, -1, "_curthread");
-		return 1;
-	}
-	std::string name = luax_checkstring(L, 1);
-	Thread *t = instance->getThread(name);
-	if (t)
-	{
-		luax_newtype(L, "Thread", THREAD_THREAD_T, (void *)t);
-		t->lock();
-		t->retain();
-		t->unlock();
-	}
-	else
-		lua_pushnil(L);
-	return 1;
-}
-
-
-// List of functions to wrap.
-static const luaL_Reg module_functions[] =
-{
-	{ "newThread", w_newThread },
-	{ "getThread", w_getThread },
-	{ "getThreads", w_getThreads },
-	{ 0, 0 }
-};
-
-static const lua_CFunction types[] =
-{
-	luaopen_thread,
-	0
-};
-
-extern "C" int luaopen_love_thread(lua_State *L)
-{
-	if (instance == 0)
-	{
-		try
-		{
-			instance = new ThreadModule();
-			lua_getglobal(L, "love");
-			Thread *curthread = instance->getThread("main");
-			curthread->lock();
-			curthread->retain();
-			curthread->unlock();
-			luax_newtype(L, "Thread", THREAD_THREAD_T, (void *)curthread);
-			lua_setfield(L, -2, "_curthread");
-		}
-		catch(Exception &e)
-		{
-			return luaL_error(L, e.what());
-		}
-	}
-	else
-		instance->retain();
-
-	WrappedModule w;
-	w.module = instance;
-	w.name = "thread";
-	w.flags = MODULE_T;
-	w.functions = module_functions;
-	w.types = types;
-
-	return luax_register_module(L, w);
-}
-
-} // thread
-} // love

+ 126 - 0
src/modules/thread/wrap_ThreadModule.cpp

@@ -0,0 +1,126 @@
+/**
+* Copyright (c) 2006-2010 LOVE Development Team
+*
+* This software is provided 'as-is', without any express or implied
+* warranty.  In no event will the authors be held liable for any damages
+* arising from the use of this software.
+*
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+*
+* 1. The origin of this software must not be misrepresented; you must not
+*    claim that you wrote the original software. If you use this software
+*    in a product, an acknowledgment in the product documentation would be
+*    appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+*    misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+**/
+
+#include "wrap_ThreadModule.h"
+#include "wrap_LuaThread.h"
+#include "wrap_Channel.h"
+#include <filesystem/File.h>
+#include <filesystem/FileData.h>
+
+namespace love
+{
+namespace thread
+{
+static ThreadModule *instance = 0;
+
+int w_newThread(lua_State *L)
+{
+	std::string name = "Thread code";
+	love::Data *data;
+	if (lua_isstring(L, 1))
+		luax_convobj(L, 1, "filesystem", "newFile");
+	if (luax_istype(L, 1, FILESYSTEM_FILE_T))
+	{
+		try
+		{
+			love::filesystem::File * file = luax_checktype<love::filesystem::File>(L, 1, "File", FILESYSTEM_FILE_T);
+			name = std::string("@") + file->getFilename();
+			data = file->read();
+		}
+		catch (love::Exception & e)
+		{
+			return luaL_error(L, "%s", e.what());
+		}
+	}
+	else if (luax_istype(L, 1, FILESYSTEM_FILE_DATA_T))
+	{
+		love::filesystem::FileData * fdata = luax_checktype<love::filesystem::FileData>(L, 1, "FileData", FILESYSTEM_FILE_DATA_T);
+		name = std::string("@") + fdata->getFilename();
+		data = fdata;
+		data->retain();
+	}
+	else
+	{
+		data = luax_checktype<love::Data>(L, 1, "Data", DATA_T);
+		data->retain();
+	}
+	LuaThread *t = instance->newThread(name, data);
+	// do not worry, file->read() returns retained data
+	data->release();
+	luax_newtype(L, "Thread", THREAD_THREAD_T, (void *)t);
+	return 1;
+}
+
+int w_newChannel(lua_State *L)
+{
+	Channel *c = instance->newChannel();
+	luax_newtype(L, "Channel", THREAD_CHANNEL_T, (void *)c);
+	return 1;
+}
+
+int w_getChannel(lua_State *L)
+{
+	std::string name = luax_checkstring(L, 1);
+	Channel *c = instance->getChannel(name);
+	luax_newtype(L, "Channel", THREAD_CHANNEL_T, (void *)c);
+	return 1;
+}
+
+// List of functions to wrap.
+static const luaL_Reg module_functions[] = {
+	{ "newThread", w_newThread },
+	{ "newChannel", w_newChannel },
+	{ "getChannel", w_getChannel },
+	{ 0, 0 }
+};
+
+static const lua_CFunction types[] = {
+	luaopen_thread,
+	luaopen_channel,
+	0
+};
+
+extern "C" int luaopen_love_thread(lua_State *L)
+{
+	if (instance == 0)
+	{
+		try
+		{
+			instance = new ThreadModule();
+		}
+		catch (Exception & e)
+		{
+			return luaL_error(L, "%s", e.what());
+		}
+	}
+	else
+		instance->retain();
+
+	WrappedModule w;
+	w.module = instance;
+	w.name = "thread";
+	w.flags = MODULE_T;
+	w.functions = module_functions;
+	w.types = types;
+
+	return luax_register_module(L, w);
+}
+}
+}

+ 40 - 0
src/modules/thread/wrap_ThreadModule.h

@@ -0,0 +1,40 @@
+/**
+* Copyright (c) 2006-2012 LOVE Development Team
+*
+* This software is provided 'as-is', without any express or implied
+* warranty.  In no event will the authors be held liable for any damages
+* arising from the use of this software.
+*
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+*
+* 1. The origin of this software must not be misrepresented; you must not
+*    claim that you wrote the original software. If you use this software
+*    in a product, an acknowledgment in the product documentation would be
+*    appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+*    misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+**/
+
+#ifndef LOVE_THREAD_WRAP_THREADMODULE_H
+#define LOVE_THREAD_WRAP_THREADMODULE_H
+
+// LOVE
+#include "ThreadModule.h"
+
+namespace love
+{
+namespace thread
+{
+int w_newThread(lua_State *L);
+int w_newChannel(lua_State *L);
+int w_getChannel(lua_State *L);
+
+extern "C" LOVE_EXPORT int luaopen_love_thread(lua_State * L);
+
+} // thread
+} // love
+
+#endif // LOVE_THREAD_WRAP_THREADMODULE_H

+ 11 - 2
src/modules/window/Window.h

@@ -33,6 +33,15 @@ namespace love
 namespace window
 {
 
+struct WindowFlags
+{
+	bool fullscreen; // = false
+	bool vsync; // = true
+	int fsaa; // = 0
+	bool resizable; // = false
+	bool borderless; // = false
+}; // WindowFlags
+
 class Window : public Module
 {
 public:
@@ -44,8 +53,8 @@ public:
 
 	virtual ~Window();
 
-	virtual bool setWindow(int width = 800, int height = 600, bool fullscreen = false, bool vsync = true, int fsaa = 0) = 0;
-	virtual void getWindow(int &width, int &height, bool &fullscreen, bool &vsync, int &fsaa) const = 0;
+	virtual bool setWindow(int width = 800, int height = 600, WindowFlags *flags = 0) = 0;
+	virtual void getWindow(int &width, int &height, WindowFlags &flags) const = 0;
 
 	virtual bool checkWindowSize(int width, int height, bool fullscreen) const = 0;
 	virtual WindowSize **getFullscreenSizes(int &n) const = 0;

+ 34 - 8
src/modules/window/sdl/Window.cpp

@@ -56,8 +56,23 @@ Window::_currentMode::_currentMode()
 {
 }
 
-bool Window::setWindow(int width, int height, bool fullscreen, bool vsync, int fsaa)
+bool Window::setWindow(int width, int height, WindowFlags *flags)
 {
+	bool fullscreen = false;
+	bool vsync = true;
+	int fsaa = 0;
+	bool resizable = false;
+	bool borderless = false;
+
+	if (flags)
+	{
+		fullscreen = flags->fullscreen;
+		vsync = flags->vsync;
+		fsaa = flags->fsaa;
+		resizable = flags->resizable;
+		borderless = flags->borderless;
+	}
+
 	bool mouseVisible = getMouseVisible();
 	int keyrepeatDelay, keyrepeatInterval;
 	SDL_GetKeyRepeat(&keyrepeatDelay, &keyrepeatInterval);
@@ -100,11 +115,18 @@ bool Window::setWindow(int width, int height, bool fullscreen, bool vsync, int f
 	SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, (fsaa > 0) ? 1 : 0);
 	SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, (fsaa > 0) ? fsaa : 0);
 
-	// Fullscreen?
-	Uint32 sdlflags = fullscreen ? (SDL_OPENGL | SDL_FULLSCREEN) : SDL_OPENGL;
+	Uint32 sdlflags = SDL_OPENGL;
+	// Flags
+	if (fullscreen)
+		sdlflags |= SDL_FULLSCREEN;
+	if (resizable)
+		sdlflags |= SDL_RESIZABLE;
+	if (borderless)
+		sdlflags |= SDL_NOFRAME;
 
 	// Have SDL set the video mode.
-	if (SDL_SetVideoMode(width, height, 32, sdlflags) == 0)
+	SDL_Surface *surface;
+	if ((surface = SDL_SetVideoMode(width, height, 32, sdlflags)) == 0)
 	{
 		bool failed = true;
 		if (fsaa > 0)
@@ -153,17 +175,21 @@ bool Window::setWindow(int width, int height, bool fullscreen, bool vsync, int f
 	currentMode.fsaa = fsaa;
 	currentMode.fullscreen = fullscreen;
 	currentMode.vsync = (real_vsync != 0);
+	currentMode.resizable = ((surface->flags & SDL_RESIZABLE) != 0);
+	currentMode.borderless = ((surface->flags & SDL_NOFRAME) != 0);
 
 	return true;
 }
 
-void Window::getWindow(int &width, int &height, bool &fullscreen, bool &vsync, int &fsaa) const
+void Window::getWindow(int &width, int &height, WindowFlags &flags) const
 {
 	width = currentMode.width;
 	height = currentMode.height;
-	fullscreen = currentMode.fullscreen;
-	vsync = currentMode.vsync;
-	fsaa = currentMode.fsaa;
+	flags.fullscreen = currentMode.fullscreen;
+	flags.vsync = currentMode.vsync;
+	flags.fsaa = currentMode.fsaa;
+	flags.resizable = currentMode.resizable;
+	flags.borderless = currentMode.borderless;
 }
 
 bool Window::checkWindowSize(int width, int height, bool fullscreen) const

+ 4 - 2
src/modules/window/sdl/Window.h

@@ -37,8 +37,8 @@ public:
 	Window();
 	~Window();
 
-	bool setWindow(int width = 800, int height = 600, bool fullscreen = false, bool vsync = true, int fsaa = 0);
-	void getWindow(int &width, int &height, bool &fullscreen, bool &vsync, int &fsaa) const;
+	bool setWindow(int width = 800, int height = 600, WindowFlags *flags = 0);
+	void getWindow(int &width, int &height, WindowFlags &flags) const;
 
 	bool checkWindowSize(int width, int height, bool fullscreen) const;
 	WindowSize **getFullscreenSizes(int &n) const;
@@ -72,6 +72,8 @@ private:
 		bool fullscreen;
 		bool vsync;
 		int fsaa;
+		bool resizable;
+		bool borderless;
 	} currentMode;
 	bool created;
 }; // Window

+ 13 - 1
src/scripts/boot.lua

@@ -179,6 +179,11 @@ function love.createhandlers()
 		quit = function ()
 			return
 		end,
+		resize = function(w, h)
+			local ow, oh, flags = love.graphics.getMode()
+			love.graphics.setMode(w, h, flags)
+			if love.resize then love.resize(w, h) end
+		end,
 	}, {
 		__index = function(self, name)
 			error("Unknown event: " .. name)
@@ -324,7 +329,14 @@ function love.init()
 	local has_window = false
 	if c.screen and c.modules.graphics then
 		if love.graphics.checkMode(c.screen.width, c.screen.height, c.screen.fullscreen) or (c.screen.width == 0 and c.screen.height == 0) then
-			has_window = assert(love.graphics.setMode(c.screen.width, c.screen.height, c.screen.fullscreen, c.screen.vsync, c.screen.fsaa), "Could not set screen mode")
+			assert(love.graphics.setMode(c.screen.width, c.screen.height,
+			{
+				fullscreen = c.screen.fullscreen,
+				vsync = c.screen.vsync,
+				fsaa = c.screen.fsaa,
+				resizable = c.screen.resizable,
+				borderless = c.screen.borderless,
+			}), "Could not set screen mode")
 		else
 			error("Could not set screen mode")
 		end

+ 31 - 9
src/scripts/boot.lua.h

@@ -309,6 +309,18 @@ const unsigned char boot_lua[] =
 	0x28, 0x29, 0x0a,
 	0x09, 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x0a,
 	0x09, 0x09, 0x65, 0x6e, 0x64, 0x2c, 0x0a,
+	0x09, 0x09, 0x72, 0x65, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 
+	0x6e, 0x28, 0x77, 0x2c, 0x20, 0x68, 0x29, 0x0a,
+	0x09, 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6f, 0x77, 0x2c, 0x20, 0x6f, 0x68, 0x2c, 0x20, 0x66, 
+	0x6c, 0x61, 0x67, 0x73, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 
+	0x63, 0x73, 0x2e, 0x67, 0x65, 0x74, 0x4d, 0x6f, 0x64, 0x65, 0x28, 0x29, 0x0a,
+	0x09, 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x73, 
+	0x65, 0x74, 0x4d, 0x6f, 0x64, 0x65, 0x28, 0x77, 0x2c, 0x20, 0x68, 0x2c, 0x20, 0x66, 0x6c, 0x61, 0x67, 0x73, 
+	0x29, 0x0a,
+	0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x72, 0x65, 0x73, 0x69, 0x7a, 0x65, 0x20, 
+	0x74, 0x68, 0x65, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x72, 0x65, 0x73, 0x69, 0x7a, 0x65, 0x28, 0x77, 
+	0x2c, 0x20, 0x68, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a,
+	0x09, 0x09, 0x65, 0x6e, 0x64, 0x2c, 0x0a,
 	0x09, 0x7d, 0x2c, 0x20, 0x7b, 0x0a,
 	0x09, 0x09, 0x5f, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 
 	0x6f, 0x6e, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2c, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x0a,
@@ -531,15 +543,25 @@ const unsigned char boot_lua[] =
 	0x63, 0x72, 0x65, 0x65, 0x6e, 0x2e, 0x77, 0x69, 0x64, 0x74, 0x68, 0x20, 0x3d, 0x3d, 0x20, 0x30, 0x20, 0x61, 
 	0x6e, 0x64, 0x20, 0x63, 0x2e, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x2e, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 
 	0x20, 0x3d, 0x3d, 0x20, 0x30, 0x29, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a,
-	0x09, 0x09, 0x09, 0x68, 0x61, 0x73, 0x5f, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x20, 0x3d, 0x20, 0x61, 0x73, 
-	0x73, 0x65, 0x72, 0x74, 0x28, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 
-	0x2e, 0x73, 0x65, 0x74, 0x4d, 0x6f, 0x64, 0x65, 0x28, 0x63, 0x2e, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x2e, 
-	0x77, 0x69, 0x64, 0x74, 0x68, 0x2c, 0x20, 0x63, 0x2e, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x2e, 0x68, 0x65, 
-	0x69, 0x67, 0x68, 0x74, 0x2c, 0x20, 0x63, 0x2e, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x2e, 0x66, 0x75, 0x6c, 
-	0x6c, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x2c, 0x20, 0x63, 0x2e, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x2e, 
-	0x76, 0x73, 0x79, 0x6e, 0x63, 0x2c, 0x20, 0x63, 0x2e, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x2e, 0x66, 0x73, 
-	0x61, 0x61, 0x29, 0x2c, 0x20, 0x22, 0x43, 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x73, 0x65, 
-	0x74, 0x20, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x20, 0x6d, 0x6f, 0x64, 0x65, 0x22, 0x29, 0x0a,
+	0x09, 0x09, 0x09, 0x61, 0x73, 0x73, 0x65, 0x72, 0x74, 0x28, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 
+	0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x73, 0x65, 0x74, 0x4d, 0x6f, 0x64, 0x65, 0x28, 0x63, 0x2e, 0x73, 0x63, 
+	0x72, 0x65, 0x65, 0x6e, 0x2e, 0x77, 0x69, 0x64, 0x74, 0x68, 0x2c, 0x20, 0x63, 0x2e, 0x73, 0x63, 0x72, 0x65, 
+	0x65, 0x6e, 0x2e, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x2c, 0x0a,
+	0x09, 0x09, 0x09, 0x7b, 0x0a,
+	0x09, 0x09, 0x09, 0x09, 0x66, 0x75, 0x6c, 0x6c, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x20, 0x3d, 0x20, 0x63, 
+	0x2e, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x2e, 0x66, 0x75, 0x6c, 0x6c, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 
+	0x2c, 0x0a,
+	0x09, 0x09, 0x09, 0x09, 0x76, 0x73, 0x79, 0x6e, 0x63, 0x20, 0x3d, 0x20, 0x63, 0x2e, 0x73, 0x63, 0x72, 0x65, 
+	0x65, 0x6e, 0x2e, 0x76, 0x73, 0x79, 0x6e, 0x63, 0x2c, 0x0a,
+	0x09, 0x09, 0x09, 0x09, 0x66, 0x73, 0x61, 0x61, 0x20, 0x3d, 0x20, 0x63, 0x2e, 0x73, 0x63, 0x72, 0x65, 0x65, 
+	0x6e, 0x2e, 0x66, 0x73, 0x61, 0x61, 0x2c, 0x0a,
+	0x09, 0x09, 0x09, 0x09, 0x72, 0x65, 0x73, 0x69, 0x7a, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0x63, 0x2e, 
+	0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x2e, 0x72, 0x65, 0x73, 0x69, 0x7a, 0x61, 0x62, 0x6c, 0x65, 0x2c, 0x0a,
+	0x09, 0x09, 0x09, 0x09, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x6c, 0x65, 0x73, 0x73, 0x20, 0x3d, 0x20, 0x63, 
+	0x2e, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x2e, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x6c, 0x65, 0x73, 0x73, 
+	0x2c, 0x0a,
+	0x09, 0x09, 0x09, 0x7d, 0x29, 0x2c, 0x20, 0x22, 0x43, 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x6e, 0x6f, 0x74, 0x20, 
+	0x73, 0x65, 0x74, 0x20, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x20, 0x6d, 0x6f, 0x64, 0x65, 0x22, 0x29, 0x0a,
 	0x09, 0x09, 0x65, 0x6c, 0x73, 0x65, 0x0a,
 	0x09, 0x09, 0x09, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x28, 0x22, 0x43, 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x6e, 0x6f, 
 	0x74, 0x20, 0x73, 0x65, 0x74, 0x20, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x20, 0x6d, 0x6f, 0x64, 0x65, 0x22,