Merge branch 'master' into multi-monitor

Conflicts:
	include/GL/glfw3.h
diff --git a/.gitignore b/.gitignore
index da61d80..1366b5f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,9 +1,9 @@
+.DS_Store
+Makefile
+CMakeCache.txt
 CMakeFiles
 cmake_install.cmake
-CMakeCache.txt
-Makefile
 cmake_uninstall.cmake
-.DS_Store
 docs/Doxyfile
 src/config.h
 src/glfw3.pc
@@ -13,14 +13,17 @@
 src/glfw3.lib
 src/glfw3.dll
 src/glfw3dll.lib
+examples/*.app
+examples/*.exe
 examples/boing
 examples/gears
 examples/heightmap
 examples/splitview
 examples/triangle
 examples/wave
-examples/*.app
-examples/*.exe
+src/config.h
+tests/*.app
+tests/*.exe
 tests/accuracy
 tests/clipboard
 tests/defaults
@@ -38,6 +41,5 @@
 tests/tearing
 tests/threads
 tests/title
+tests/version
 tests/windows
-tests/*.app
-tests/*.exe
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 08542a6..ba257c9 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -30,15 +30,6 @@
     find_package(OpenGL REQUIRED)
 endif()
 
-if (NOT WIN32)
-    set(CMAKE_THREAD_PREFER_PTHREADS YES)
-endif()
-
-find_package(Threads)
-if (CMAKE_THREAD_LIBS_INIT)
-    list(APPEND glfw_LIBRARIES ${CMAKE_THREAD_LIBS_INIT})
-endif()
-
 #--------------------------------------------------------------------
 # Enable all warnings on GCC, regardless of OS
 #--------------------------------------------------------------------
diff --git a/examples/boing.c b/examples/boing.c
index 5a1993f..a5914f9 100644
--- a/examples/boing.c
+++ b/examples/boing.c
@@ -579,7 +579,7 @@
 
    glfwWindowHint(GLFW_DEPTH_BITS, 16);
 
-   window = glfwCreateWindow( 400, 400, GLFW_WINDOWED, "Boing (classic Amiga demo)", NULL );
+   window = glfwCreateWindow( 400, 400, "Boing (classic Amiga demo)", NULL, NULL );
    if (!window)
    {
        fprintf( stderr, "Failed to open GLFW window\n" );
diff --git a/examples/gears.c b/examples/gears.c
index b056251..cc4b29a 100644
--- a/examples/gears.c
+++ b/examples/gears.c
@@ -340,7 +340,7 @@
 
     glfwWindowHint(GLFW_DEPTH_BITS, 16);
 
-    window = glfwCreateWindow( 300, 300, GLFW_WINDOWED, "Gears", NULL );
+    window = glfwCreateWindow( 300, 300, "Gears", NULL, NULL );
     if (!window)
     {
         fprintf( stderr, "Failed to open GLFW window\n" );
diff --git a/examples/heightmap.c b/examples/heightmap.c
index 5436a18..de15feb 100644
--- a/examples/heightmap.c
+++ b/examples/heightmap.c
@@ -587,7 +587,7 @@
     glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
     glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_FALSE);
 
-    window = glfwCreateWindow(800, 600, GLFW_WINDOWED, "GLFW OpenGL3 Heightmap demo", NULL);
+    window = glfwCreateWindow(800, 600, "GLFW OpenGL3 Heightmap demo", NULL, NULL);
     if (! window )
     {
         fprintf(stderr, "ERROR: Unable to create the OpenGL context and associated window\n");
diff --git a/examples/splitview.c b/examples/splitview.c
index 965a183..9b3e085 100644
--- a/examples/splitview.c
+++ b/examples/splitview.c
@@ -453,7 +453,7 @@
     glfwWindowHint(GLFW_DEPTH_BITS, 16);
 
     // Open OpenGL window
-    window = glfwCreateWindow(500, 500, GLFW_WINDOWED, "Split view demo", NULL);
+    window = glfwCreateWindow(500, 500, "Split view demo", NULL, NULL);
     if (!window)
     {
         fprintf(stderr, "Failed to open GLFW window\n");
diff --git a/examples/triangle.c b/examples/triangle.c
index 3a1cef9..52e1149 100644
--- a/examples/triangle.c
+++ b/examples/triangle.c
@@ -23,7 +23,7 @@
     }
 
     // Open a window and create its OpenGL context
-    window = glfwCreateWindow(640, 480, GLFW_WINDOWED, "Spinning Triangle", NULL);
+    window = glfwCreateWindow(640, 480, "Spinning Triangle", NULL, NULL);
     if (!window)
     {
         fprintf(stderr, "Failed to open GLFW window\n");
diff --git a/examples/wave.c b/examples/wave.c
index 7b4b4c3..a1bfde5 100644
--- a/examples/wave.c
+++ b/examples/wave.c
@@ -399,7 +399,7 @@
         exit(EXIT_FAILURE);
     }
 
-    window = glfwCreateWindow(640, 480, GLFW_WINDOWED, "Wave Simulation", NULL);
+    window = glfwCreateWindow(640, 480, "Wave Simulation", NULL, NULL);
     if (!window)
     {
         fprintf(stderr, "Could not open window\n");
diff --git a/include/GL/glfw3.h b/include/GL/glfw3.h
index 237f7e1..539c2de 100644
--- a/include/GL/glfw3.h
+++ b/include/GL/glfw3.h
@@ -58,6 +58,8 @@
  */
 /*! @defgroup input Input handling
  */
+/*! @defgroup monitor Monitor handling
+ */
 /*! @defgroup time Time input
  */
 /*! @defgroup window Window handling
@@ -67,8 +69,6 @@
  *  multiple windows, which can be either a normal desktop window or
  *  a fullscreen window.
  */
-/*! @defgroup monitor Monitor handling
- */
 
 
 /*************************************************************************
@@ -454,15 +454,6 @@
  * Other definitions
  *************************************************************************/
 
-/*! @brief A regular, overlapped window.
- *  @ingroup window
- */
-#define GLFW_WINDOWED             0x00010001
-/*! @brief A fullscreen window that may changed the monitor's resolution.
- *  @ingroup window
- */
-#define GLFW_FULLSCREEN           0x00010002
-
 /*! @defgroup paramhints Window parameters and hints
  *  @ingroup window
  *  @{ */
@@ -694,6 +685,39 @@
  */
 #define GLFW_GAMMA_RAMP_SIZE      256
 
+/*! @name Monitor parameters
+ *  @{ */
+/*! @brief The physical width, in mm, of the monitor.
+ *  @ingroup monitor
+ */
+#define GLFW_MONITOR_WIDTH_MM         0x00060001
+/*! @brief The physical height, in mm, of the monitor.
+ *  @ingroup monitor
+ */
+#define GLFW_MONITOR_HEIGHT_MM        0x00060002
+/*! @brief The x-coordinate of the upper-left corner of the monitor on the
+ *  virtual desktop.
+ *  @ingroup monitor
+ */
+#define GLFW_MONITOR_POS_X            0x00060003
+/*! @brief The y-coordinate of the upper-left corner of the monitor on the
+ *  virtual desktop.
+ *  @ingroup monitor
+ */
+#define GLFW_MONITOR_POS_Y            0x00060004
+/* @} */
+
+/*! @name Monitor events
+ *  @{ */
+/*! @brief The monitor was connected.
+ *  @ingroup monitor
+ */
+#define GLFW_CONNECTED                0x00061000
+/*! @brief The monitor was disconnected.
+ *  @ingroup monitor
+ */
+#define GLFW_DISCONNECTED             0x00061001
+/* @} */
 
 /*************************************************************************
  * Typedefs
@@ -704,6 +728,11 @@
  */
 typedef void (*GLFWglproc)(void);
 
+/*! @brief Monitor handle type.
+ *  @ingroup monitor
+ */
+typedef void* GLFWmonitor;
+
 /*! @brief Window handle type.
  *  @ingroup window
  */
@@ -813,6 +842,13 @@
  */
 typedef void (* GLFWcharfun)(GLFWwindow,int);
 
+/*! @brief The function signature for monitor configuration callbacks.
+ *  @param[in] monitor The monitor that was connected or disconnected.
+ *  @param[in] event @ref GLFW_MONITOR_CONNECTED or @ref
+ *  GLFW_MONITOR_DISCONNECTED.
+ */
+typedef void (* GLFWmonitorfun)(GLFWmonitor,int);
+
 /* @brief Video mode type.
  * @ingroup monitor
  */
@@ -950,17 +986,68 @@
  */
 GLFWAPI void glfwSetErrorCallback(GLFWerrorfun cbfun);
 
-/*! @brief This function will be replaced when the @c multi-monitor branch is
- *  merged.
+/*! @brief Returns the currently connected monitors.
+ *  @param[out] count The size of the returned array.
+ *  @return An array of monitor handles.
  *  @ingroup monitor
  */
-GLFWAPI GLFWvidmode* glfwGetVideoModes(int* count);
+GLFWAPI const GLFWmonitor* glfwGetMonitors(int* count);
 
-/*! @brief This function will be replaced when the @c multi-monitor branch is
- *  merged.
+/*! @brief Returns the primary monitor.
+ *  @return The primary monitor.
  *  @ingroup monitor
  */
-GLFWAPI void glfwGetDesktopMode(GLFWvidmode* mode);
+GLFWAPI GLFWmonitor glfwGetPrimaryMonitor(void);
+
+/*! @brief Returns a property of the specified monitor.
+ *  @ingroup monitor
+ */
+GLFWAPI int glfwGetMonitorParam(GLFWmonitor monitor, int param);
+
+/*! @brief Returns the name of the specified monitor.
+ *  @param[in] monitor The monitor to query.
+ *  @return The UTF-8 encoded name of the monitor.
+ *  @ingroup monitor
+ */
+GLFWAPI const char* glfwGetMonitorName(GLFWmonitor monitor);
+
+/*! @brief Sets the user pointer of the specified monitor.
+ *  @param[in] monitor The monitor whose pointer to set.
+ *  @param[in] pointer The new value.
+ *  @ingroup monitor
+ *
+ *  @see glfwGetMonitorUserPointer
+ */
+GLFWAPI void glfwSetMonitorUserPointer(GLFWmonitor monitor, void* pointer);
+
+/*! @brief Returns the user pointer of the specified monitor.
+ *  @param[in] monitor The monitor whose pointer to return.
+ *  @ingroup monitor
+ *
+ *  @sa glfwSetMonitorUserPointer
+ */
+GLFWAPI void* glfwGetMonitorUserPointer(GLFWmonitor monitor);
+
+/*! @brief Sets the monitor configuration callback.
+ *  @param[in] cbfun The new callback, or @c NULL to remove the currently set.
+ *  @ingroup monitor
+ */
+GLFWAPI void glfwSetMonitorCallback(GLFWmonitorfun cbfun);
+
+/*! @brief Returns the available video modes for the specified monitor.
+ *  @param[in] monitor The monitor to query.
+ *  @param[out] count The number of video modes in the returned array.
+ *  @return An array of video modes.
+ *  @ingroup monitor
+ */
+GLFWAPI const GLFWvidmode* glfwGetVideoModes(GLFWmonitor monitor, int* count);
+
+/*! @brief Returns the current mode of the specified monitor.
+ *  @param[in] monitor The monitor to query.
+ *  @param[out] mode The current mode of the monitor.
+ *  @ingroup monitor
+ */
+GLFWAPI void glfwGetVideoMode(GLFWmonitor monitor, GLFWvidmode* mode);
 
 /*! @brief Sets the system gamma ramp to one generated from the specified
  *  exponent.
@@ -1100,8 +1187,9 @@
  *  greater than zero.
  *  @param[in] height The desired height, in pixels, of the window.  This must
  *  be greater than zero.
- *  @param[in] mode One of @ref GLFW_WINDOWED or @ref GLFW_FULLSCREEN.
  *  @param[in] title The initial, UTF-8 encoded window title.
+ *  @param[in] monitor The monitor to use for fullscreen mode, or @c NULL to use
+ *  windowed mode.
  *  @param[in] share The window whose context to share resources with, or @c
  *  NULL to not share resources.
  *  @return The handle of the created window, or @c NULL if an error occurred.
@@ -1137,7 +1225,7 @@
  *
  *  @sa glfwDestroyWindow
  */
-GLFWAPI GLFWwindow glfwCreateWindow(int width, int height, int mode, const char* title, GLFWwindow share);
+GLFWAPI GLFWwindow glfwCreateWindow(int width, int height, const char* title, GLFWmonitor monitor, GLFWwindow share);
 
 /*! @brief Destroys the specified window and its context.
  *  @param[in] window The window to destroy.
@@ -1241,6 +1329,13 @@
  */
 GLFWAPI void glfwHideWindow(GLFWwindow window);
 
+/*! @brief Returns the monitor that the window uses for fullscreen mode
+ *  @param[in] window The window to query.
+ *  @return The monitor, or @c NULL if the window is in windowed mode.
+ *  @ingroup window
+ */
+GLFWAPI GLFWmonitor glfwGetWindowMonitor(GLFWwindow window);
+
 /*! @brief Returns a property of the specified window.
  *  @param[in] window The window to query.
  *  @param[in] param The property whose value to return.
diff --git a/readme.html b/readme.html
index 8e25c74..190b05f 100644
--- a/readme.html
+++ b/readme.html
@@ -267,6 +267,11 @@
 
 <h3>v3.0</h3>
 <ul>
+  <li>Added <code>GLFWmonitor</code> monitor handle type and updated monitor-related functions to take a monitor handle</li>
+  <li>Added <code>glfwGetMonitors</code> and <code>glfwGetPrimaryMonitor</code> for enumerating available monitors</li>
+  <li>Added <code>glfwGetMonitorParam</code> and <code>glfwGetMonitorName</code> for retrieving monitor properties</li>
+  <li>Added <code>glfwSetMonitorUserPointer</code> and <code>glfwGetMonitorUserPointer</code> for per-monitor user pointers</li>
+  <li>Added <code>glfwSetMonitorCallback</code> and <code>GLFWmonitorfun</code> for notification of changes in the set of available monitors</li>
   <li>Added <code>GLFWwindow</code> window handle type and updated window-related functions and callbacks to take a window handle</li>
   <li>Added <code>glfwDefaultWindowHints</code> function for resetting all window hints to their default values</li>
   <li>Added <code>glfwMakeContextCurrent</code> function for making the context of the specified window current</li>
@@ -274,6 +279,7 @@
   <li>Added <code>glfwSetErrorCallback</code> function and <code>GLFWerrorfun</code> type for receiving more specific and/or nested errors</li>
   <li>Added <code>glfwSetWindowUserPointer</code> and <code>glfwGetWindowUserPointer</code> functions for per-window user pointers</li>
   <li>Added <code>glfwGetVersionString</code> function for determining which code paths were enabled at compile time</li>
+  <li>Added <code>glfwGetWindowMonitor</code> for querying the monitor, if any, of the specified window</li>
   <li>Added <code>glfwSetWindowPosCallback</code> function and <code>GLFWwindowposfun</code> type for reciving window position events</li>
   <li>Added <code>glfwSetWindowFocusCallback</code> function and <code>GLFWwindowfocusfun</code> type for receiving window focus events</li>
   <li>Added <code>glfwSetWindowIconifyCallback</code> function and <code>GLFWwindowiconifyfun</code> type for receiving window iconification events</li>
@@ -298,11 +304,10 @@
   <li>Changed buffer bit depth parameters of <code>glfwOpenWindow</code> to window hints</li>
   <li>Changed <code>glfwOpenWindow</code> and <code>glfwSetWindowTitle</code> to use UTF-8 encoded strings</li>
   <li>Changed <code>glfwGetProcAddress</code> to return a (generic) function pointer</li>
-  <li>Changed <code>glfwGetVideoModes</code> to return a dynamic, unlimited number of video modes</li>
+  <li>Changed <code>glfwGetVideoModes</code> to return a dynamic, unlimited number of video modes for the specified monitor</li>
   <li>Renamed <code>glfw.h</code> to <code>glfw3.h</code> to avoid conflicts with 2.x series</li>
   <li>Renamed <code>glfwOpenWindowHint</code> to <code>glfwWindowHint</code></li>
   <li>Renamed <code>GLFW_ACTIVE</code> to <code>GLFW_FOCUSED</code></li>
-  <li>Renamed <code>GLFW_WINDOW</code> token to <code>GLFW_WINDOWED</code></li>
   <li>Renamed <code>GLFW_WINDOW_NO_RESIZE</code> to <code>GLFW_RESIZABLE</code></li>
   <li>Renamed <code>GLFW_BUILD_DLL</code> to <code>_GLFW_BUILD_DLL</code></li>
   <li>Renamed <code>version</code> test to <code>glfwinfo</code></li>
@@ -310,6 +315,7 @@
   <li>Renamed <code>glfwGetJoystickPos</code> to <code>glfwGetJoystickAxes</code> to match <code>glfwGetJoystickButtons</code></li>
   <li>Renamed mouse position functions to cursor position equivalents</li>
   <li>Replaced <code>glfwOpenWindow</code> and <code>glfwCloseWindow</code> with <code>glfwCreateWindow</code> and <code>glfwDestroyWindow</code></li>
+  <li>Replaced <code>glfwGetDesktopMode</code> width <code>glfwGetVideoMode</code></li>
   <li>Replaced ad hoc build system with CMake</li>
   <li>Replaced layout-dependent key codes with single, platform-independent set based on US layout</li>
   <li>Replaced mouse wheel interface with two-dimensional, floating point scrolling interface</li>
@@ -327,6 +333,7 @@
   <li>Removed <code>glfwGetNumberOfProcessors</code> function</li>
   <li>Removed <code>glfwGetGLVersion</code> function</li>
   <li>Removed <code>GLFW_OPENED</code> window parameter</li>
+  <li>Removed <code>GLFW_WINDOW</code> and <code>GLFW_FULLSCREEN</code></li>
   <li>Removed nonsensical key actions for Unicode character input</li>
   <li>Removed <code>GLFWCALL</code> and <code>GLFWAPIENTRY</code> macros for stdcall calling convention</li>
   <li>Removed <code>GLFW_ACCELERATED</code> window parameter</li>
@@ -925,6 +932,9 @@
 
   <li>David Medlock, for doing the initial Lua port</li>
 
+  <li>Marcel Metz, for the initial implementation of multi-monitor support on
+  X11 and Win32</li>
+
   <li>Kenneth Miller, for his many and detailed bug reports on Win32</li>
 
   <li>Jeff Molofee, the author of the excellent OpenGL tutorials at <a
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 3d11ef3..05ee10e 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,3 +1,4 @@
+
 include_directories(${GLFW_SOURCE_DIR}/src
                     ${GLFW_BINARY_DIR}/src
                     ${glfw_INCLUDE_DIRS})
@@ -7,13 +8,13 @@
 endif()
 
 set(common_HEADERS ${GLFW_SOURCE_DIR}/include/GL/glfw3.h internal.h)
-set(common_SOURCES clipboard.c context.c fullscreen.c gamma.c init.c input.c
-                   joystick.c time.c window.c)
+set(common_SOURCES clipboard.c context.c gamma.c init.c input.c joystick.c
+                   monitor.c time.c window.c)
 
 if (_GLFW_COCOA)
     set(glfw_HEADERS ${common_HEADERS} cocoa_platform.h)
-    set(glfw_SOURCES ${common_SOURCES} cocoa_clipboard.m cocoa_fullscreen.m
-                     cocoa_gamma.c cocoa_init.m cocoa_joystick.m cocoa_time.c
+    set(glfw_SOURCES ${common_SOURCES} cocoa_clipboard.m cocoa_gamma.c
+                     cocoa_init.m cocoa_joystick.m cocoa_monitor.m cocoa_time.c
                      cocoa_window.m)
 
     if (GLFW_NATIVE_API)
@@ -21,8 +22,8 @@
     endif()
 elseif (_GLFW_WIN32)
     set(glfw_HEADERS ${common_HEADERS} win32_platform.h)
-    set(glfw_SOURCES ${common_SOURCES} win32_clipboard.c win32_fullscreen.c
-                     win32_gamma.c win32_init.c win32_joystick.c win32_time.c
+    set(glfw_SOURCES ${common_SOURCES} win32_clipboard.c win32_gamma.c
+                     win32_init.c win32_joystick.c win32_monitor.c win32_time.c
                      win32_window.c)
 
     if (GLFW_NATIVE_API)
@@ -30,8 +31,8 @@
     endif()
 elseif (_GLFW_X11)
     set(glfw_HEADERS ${common_HEADERS} x11_platform.h)
-    set(glfw_SOURCES ${common_SOURCES} x11_clipboard.c x11_fullscreen.c
-                     x11_gamma.c x11_init.c x11_joystick.c x11_keysym2unicode.c
+    set(glfw_SOURCES ${common_SOURCES} x11_clipboard.c x11_gamma.c x11_init.c
+                     x11_joystick.c x11_keysym2unicode.c x11_monitor.c
                      x11_time.c x11_window.c)
 
     if (GLFW_NATIVE_API)
diff --git a/src/cocoa_init.m b/src/cocoa_init.m
index 3bb61c1..95e752e 100644
--- a/src/cocoa_init.m
+++ b/src/cocoa_init.m
@@ -92,8 +92,6 @@
 
     changeToResourcesDirectory();
 
-    _glfwLibrary.NS.desktopMode = CGDisplayCopyDisplayMode(CGMainDisplayID());
-
     // Save the original gamma ramp
     _glfwLibrary.originalRampSize = CGDisplayGammaTableCapacity(CGMainDisplayID());
     _glfwPlatformGetGammaRamp(&_glfwLibrary.originalRamp);
@@ -135,8 +133,6 @@
     if (_glfwLibrary.rampChanged)
         _glfwPlatformSetGammaRamp(&_glfwLibrary.originalRamp);
 
-    CGDisplayModeRelease(_glfwLibrary.NS.desktopMode);
-
     [NSApp setDelegate:nil];
     [_glfwLibrary.NS.delegate release];
     _glfwLibrary.NS.delegate = nil;
diff --git a/src/cocoa_fullscreen.m b/src/cocoa_monitor.m
similarity index 66%
rename from src/cocoa_fullscreen.m
rename to src/cocoa_monitor.m
index 47f8673..46fa11e 100644
--- a/src/cocoa_fullscreen.m
+++ b/src/cocoa_monitor.m
@@ -1,10 +1,11 @@
 //========================================================================
 // GLFW - An OpenGL library
 // Platform:    Cocoa
-// API Version: 3.0
+// API version: 3.0
 // WWW:         http://www.glfw.org/
 //------------------------------------------------------------------------
-// Copyright (c) 2009-2010 Camilla Berglund <elmindreda@elmindreda.org>
+// Copyright (c) 2002-2006 Marcus Geelnard
+// Copyright (c) 2006-2010 Camilla Berglund <elmindreda@elmindreda.org>
 //
 // This software is provided 'as-is', without any express or implied
 // warranty. In no event will the authors be held liable for any damages
@@ -32,6 +33,41 @@
 #include <stdlib.h>
 #include <limits.h>
 
+#include <IOKit/graphics/IOGraphicsLib.h>
+
+
+//========================================================================
+// Get the name of the specified display
+//========================================================================
+
+const char* getDisplayName(CGDirectDisplayID displayID)
+{
+    char* name;
+    CFDictionaryRef info, names;
+    CFStringRef value;
+    CFIndex size;
+
+    info = IODisplayCreateInfoDictionary(CGDisplayIOServicePort(displayID),
+                                         kIODisplayOnlyPreferredName);
+    names = CFDictionaryGetValue(info, CFSTR(kDisplayProductName));
+
+    if (!CFDictionaryGetValueIfPresent(names, CFSTR("en_US"),
+                                       (const void**) &value))
+    {
+        CFRelease(info);
+        return strdup("Unknown");
+    }
+
+    size = CFStringGetMaximumSizeForEncoding(CFStringGetLength(value),
+                                             kCFStringEncodingUTF8);
+    name = (char*) malloc(size + 1);
+    CFStringGetCString(value, name, size, kCFStringEncodingUTF8);
+
+    CFRelease(info);
+
+    return name;
+}
+
 
 //========================================================================
 // Check whether the display mode should be included in enumeration
@@ -167,6 +203,8 @@
         return GL_FALSE;
     }
 
+    _glfwLibrary.NS.previousMode = CGDisplayCopyDisplayMode(CGMainDisplayID());
+
     CGDisplayCapture(CGMainDisplayID());
     CGDisplaySetDisplayMode(CGMainDisplayID(), bestMode, NULL);
 
@@ -182,7 +220,7 @@
 void _glfwRestoreVideoMode(void)
 {
     CGDisplaySetDisplayMode(CGMainDisplayID(),
-                            _glfwLibrary.NS.desktopMode,
+                            _glfwLibrary.NS.previousMode,
                             NULL);
 
     CGDisplayRelease(CGMainDisplayID());
@@ -194,16 +232,74 @@
 //////////////////////////////////////////////////////////////////////////
 
 //========================================================================
+// Return a list of available monitors
+//========================================================================
+
+_GLFWmonitor** _glfwPlatformGetMonitors(int* count)
+{
+    uint32_t i, found = 0, monitorCount;
+    _GLFWmonitor** monitors;
+    CGDirectDisplayID* displays;
+
+    *count = 0;
+
+    CGGetActiveDisplayList(0, NULL, &monitorCount);
+
+    displays = (CGDirectDisplayID*) calloc(monitorCount, sizeof(CGDirectDisplayID));
+    if (!displays)
+    {
+        _glfwSetError(GLFW_OUT_OF_MEMORY, NULL);
+        return NULL;
+    }
+
+    monitors = (_GLFWmonitor**) calloc(monitorCount, sizeof(_GLFWmonitor*));
+    if (!monitors)
+    {
+        _glfwSetError(GLFW_OUT_OF_MEMORY, NULL);
+        return NULL;
+    }
+
+    for (i = 0;  i < monitorCount;  i++)
+    {
+        const CGSize size = CGDisplayScreenSize(displays[i]);
+        const CGRect bounds = CGDisplayBounds(displays[i]);
+
+        monitors[found] = _glfwCreateMonitor(getDisplayName(displays[i]),
+                                             CGDisplayIsMain(displays[i]),
+                                             size.width, size.height,
+                                             bounds.origin.x, bounds.origin.y);
+
+        monitors[found]->NS.displayID = displays[i];
+        found++;
+    }
+
+    free(displays);
+
+    *count = monitorCount;
+    return monitors;
+}
+
+
+//========================================================================
+// Destroy a monitor struct
+//========================================================================
+
+void _glfwPlatformDestroyMonitor(_GLFWmonitor* monitor)
+{
+}
+
+
+//========================================================================
 // Get a list of available video modes
 //========================================================================
 
-GLFWvidmode* _glfwPlatformGetVideoModes(int* found)
+GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found)
 {
     CFArrayRef modes;
     CFIndex count, i;
     GLFWvidmode* result;
 
-    modes = CGDisplayCopyAllDisplayModes(CGMainDisplayID(), NULL);
+    modes = CGDisplayCopyAllDisplayModes(monitor->NS.displayID, NULL);
     count = CFArrayGetCount(modes);
 
     result = (GLFWvidmode*) malloc(sizeof(GLFWvidmode) * count);
@@ -227,11 +323,15 @@
 
 
 //========================================================================
-// Get the desktop video mode
+// Get the current video mode for the specified monitor
 //========================================================================
 
-void _glfwPlatformGetDesktopMode(GLFWvidmode *mode)
+void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode *mode)
 {
-    *mode = vidmodeFromCGDisplayMode(_glfwLibrary.NS.desktopMode);
+    CGDisplayModeRef displayMode;
+
+    displayMode = CGDisplayCopyDisplayMode(monitor->NS.displayID);
+    *mode = vidmodeFromCGDisplayMode(displayMode);
+    CGDisplayModeRelease(displayMode);
 }
 
diff --git a/src/cocoa_platform.h b/src/cocoa_platform.h
index 21589a6..51fecbb 100644
--- a/src/cocoa_platform.h
+++ b/src/cocoa_platform.h
@@ -48,6 +48,7 @@
 
 #define _GLFW_PLATFORM_WINDOW_STATE         _GLFWwindowNS  NS
 #define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryNS NS
+#define _GLFW_PLATFORM_MONITOR_STATE        _GLFWmonitorNS NS
 
 
 //========================================================================
@@ -82,7 +83,7 @@
         double resolution;
     } timer;
 
-    CGDisplayModeRef desktopMode;
+    CGDisplayModeRef previousMode;
     CGEventSourceRef eventSource;
     id               delegate;
     id               autoreleasePool;
@@ -91,6 +92,16 @@
 } _GLFWlibraryNS;
 
 
+//------------------------------------------------------------------------
+// Platform-specific monitor structure
+//------------------------------------------------------------------------
+typedef struct _GLFWmonitorNS
+{
+    CGDirectDisplayID displayID;
+
+} _GLFWmonitorNS;
+
+
 //========================================================================
 // Prototypes for platform specific internal functions
 //========================================================================
diff --git a/src/cocoa_window.m b/src/cocoa_window.m
index 040277a..d8f5a4e 100644
--- a/src/cocoa_window.m
+++ b/src/cocoa_window.m
@@ -673,7 +673,9 @@
 {
     unsigned int styleMask = 0;
 
-    if (wndconfig->mode == GLFW_WINDOWED)
+    if (wndconfig->monitor)
+        styleMask = NSBorderlessWindowMask;
+    else
     {
         styleMask = NSTitledWindowMask | NSClosableWindowMask |
                     NSMiniaturizableWindowMask;
@@ -681,8 +683,6 @@
         if (wndconfig->resizable)
             styleMask |= NSResizableWindowMask;
     }
-    else
-        styleMask = NSBorderlessWindowMask;
 
     window->NS.object = [[NSWindow alloc]
         initWithContentRect:NSMakeRect(wndconfig->positionX, wndconfig->positionY, window->width, window->height)
@@ -794,7 +794,7 @@
 
     ADD_ATTR(NSOpenGLPFADoubleBuffer);
 
-    if (wndconfig->mode == GLFW_FULLSCREEN)
+    if (wndconfig->monitor)
     {
         ADD_ATTR(NSOpenGLPFANoRecovery);
         ADD_ATTR2(NSOpenGLPFAScreenMask,
@@ -928,7 +928,7 @@
 
     [window->NSGL.context setView:[window->NS.object contentView]];
 
-    if (wndconfig->mode == GLFW_FULLSCREEN)
+    if (wndconfig->monitor)
     {
         int bpp = colorBits + fbconfig->alphaBits;
 
@@ -961,7 +961,7 @@
 {
     [window->NS.object orderOut:nil];
 
-    if (window->mode == GLFW_FULLSCREEN)
+    if (window->monitor)
     {
         [[window->NS.object contentView] exitFullScreenModeWithOptions:nil];
 
@@ -1064,19 +1064,17 @@
 
 void _glfwPlatformPollEvents(void)
 {
-    NSEvent* event;
-
-    do
+    for (;;)
     {
-        event = [NSApp nextEventMatchingMask:NSAnyEventMask
-                                   untilDate:[NSDate distantPast]
-                                      inMode:NSDefaultRunLoopMode
-                                     dequeue:YES];
+        NSEvent* event = [NSApp nextEventMatchingMask:NSAnyEventMask
+                                            untilDate:[NSDate distantPast]
+                                               inMode:NSDefaultRunLoopMode
+                                              dequeue:YES];
+        if (event == nil)
+            break;
 
-        if (event)
-            [NSApp sendEvent:event];
+        [NSApp sendEvent:event];
     }
-    while (event);
 
     [_glfwLibrary.NS.autoreleasePool drain];
     _glfwLibrary.NS.autoreleasePool = [[NSAutoreleasePool alloc] init];
@@ -1087,7 +1085,7 @@
 // Wait for new window and input events
 //========================================================================
 
-void _glfwPlatformWaitEvents( void )
+void _glfwPlatformWaitEvents(void)
 {
     // I wanted to pass NO to dequeue:, and rely on PollEvents to
     // dequeue and send.  For reasons not at all clear to me, passing
@@ -1108,7 +1106,7 @@
 
 void _glfwPlatformSetCursorPos(_GLFWwindow* window, int x, int y)
 {
-    if (window->mode == GLFW_FULLSCREEN)
+    if (window->monitor)
     {
         CGPoint globalPoint = CGPointMake(x, y);
         CGDisplayMoveCursorToPoint(CGMainDisplayID(), globalPoint);
diff --git a/src/fullscreen.c b/src/fullscreen.c
deleted file mode 100644
index f59046d..0000000
--- a/src/fullscreen.c
+++ /dev/null
@@ -1,162 +0,0 @@
-//========================================================================
-// GLFW - An OpenGL library
-// Platform:    Any
-// API version: 3.0
-// WWW:         http://www.glfw.org/
-//------------------------------------------------------------------------
-// Copyright (c) 2002-2006 Marcus Geelnard
-// Copyright (c) 2006-2010 Camilla Berglund <elmindreda@elmindreda.org>
-// Copyright (c) 2012 Torsten Walluhn <tw@mad-cad.net>
-//
-// 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 "internal.h"
-
-#include <stdlib.h>
-#if defined(_MSC_VER)
- #include <malloc.h>
-#endif
-
-
-//========================================================================
-// Lexical comparison function for GLFW video modes, used by qsort
-//========================================================================
-
-static int compareVideoModes(const void* firstPtr, const void* secondPtr)
-{
-    int firstBPP, secondBPP, firstSize, secondSize;
-    GLFWvidmode* first = (GLFWvidmode*) firstPtr;
-    GLFWvidmode* second = (GLFWvidmode*) secondPtr;
-
-    // First sort on color bits per pixel
-
-    firstBPP = first->redBits +
-               first->greenBits +
-               first->blueBits;
-    secondBPP = second->redBits +
-                second->greenBits +
-                second->blueBits;
-
-    if (firstBPP != secondBPP)
-        return firstBPP - secondBPP;
-
-    // Then sort on screen area, in pixels
-
-    firstSize = first->width * first->height;
-    secondSize = second->width * second->height;
-
-    return firstSize - secondSize;
-}
-
-
-//////////////////////////////////////////////////////////////////////////
-//////                       GLFW internal API                      //////
-//////////////////////////////////////////////////////////////////////////
-
-//========================================================================
-// Lexical comparison of GLFW video modes
-//========================================================================
-
-int _glfwCompareVideoModes(const GLFWvidmode* first, const GLFWvidmode* second)
-{
-    return compareVideoModes(first, second);
-}
-
-
-//========================================================================
-// Convert BPP to RGB bits based on "best guess"
-//========================================================================
-
-void _glfwSplitBPP(int bpp, int* red, int* green, int* blue)
-{
-    int delta;
-
-    // We assume that by 32 the user really meant 24
-    if (bpp == 32)
-        bpp = 24;
-
-    // Convert "bits per pixel" to red, green & blue sizes
-
-    *red = *green = *blue = bpp / 3;
-    delta = bpp - (*red * 3);
-    if (delta >= 1)
-        *green = *green + 1;
-
-    if (delta == 2)
-        *red = *red + 1;
-}
-
-
-//////////////////////////////////////////////////////////////////////////
-//////                        GLFW public API                       //////
-//////////////////////////////////////////////////////////////////////////
-
-//========================================================================
-// Get a list of available video modes
-//========================================================================
-
-GLFWAPI GLFWvidmode* glfwGetVideoModes(int* count)
-{
-    if (!_glfwInitialized)
-    {
-        _glfwSetError(GLFW_NOT_INITIALIZED, NULL);
-        return NULL;
-    }
-
-    if (count == NULL)
-    {
-        _glfwSetError(GLFW_INVALID_VALUE, NULL);
-        return NULL;
-    }
-
-    free(_glfwLibrary.modes);
-
-    _glfwLibrary.modes = _glfwPlatformGetVideoModes(count);
-    if (_glfwLibrary.modes)
-        qsort(_glfwLibrary.modes, *count, sizeof(GLFWvidmode), compareVideoModes);
-
-    return _glfwLibrary.modes;
-}
-
-
-//========================================================================
-// Get the desktop video mode
-//========================================================================
-
-GLFWAPI void glfwGetDesktopMode(GLFWvidmode* mode)
-{
-    if (!_glfwInitialized)
-    {
-        _glfwSetError(GLFW_NOT_INITIALIZED, NULL);
-        return;
-    }
-
-    if (mode == NULL)
-    {
-        _glfwSetError(GLFW_INVALID_VALUE,
-                      "glfwGetDesktopMode: Parameter 'mode' cannot be NULL");
-        return;
-    }
-
-    _glfwPlatformGetDesktopMode(mode);
-}
-
diff --git a/src/init.c b/src/init.c
index 4d7b731..e0a1e6f 100644
--- a/src/init.c
+++ b/src/init.c
@@ -127,6 +127,13 @@
         return GL_FALSE;
     }
 
+    _glfwLibrary.monitors = _glfwPlatformGetMonitors(&_glfwLibrary.monitorCount);
+    if (!_glfwLibrary.monitors)
+    {
+        _glfwPlatformTerminate();
+        return GL_FALSE;
+    }
+
     _glfwInitialized = GL_TRUE;
 
     // Not all window hints have zero as their default value
@@ -149,12 +156,11 @@
     while (_glfwLibrary.windowListHead)
         glfwDestroyWindow(_glfwLibrary.windowListHead);
 
+    _glfwDestroyMonitors();
+
     if (!_glfwPlatformTerminate())
         return;
 
-    if (_glfwLibrary.modes)
-        free(_glfwLibrary.modes);
-
     _glfwInitialized = GL_FALSE;
 }
 
diff --git a/src/internal.h b/src/internal.h
index d2619e2..1ca3b11 100644
--- a/src/internal.h
+++ b/src/internal.h
@@ -49,6 +49,7 @@
 typedef struct _GLFWfbconfig    _GLFWfbconfig;
 typedef struct _GLFWwindow      _GLFWwindow;
 typedef struct _GLFWlibrary     _GLFWlibrary;
+typedef struct _GLFWmonitor     _GLFWmonitor;
 
 
 //------------------------------------------------------------------------
@@ -121,7 +122,6 @@
 //------------------------------------------------------------------------
 struct _GLFWwndconfig
 {
-    int           mode;
     const char*   title;
     int           refreshRate;
     GLboolean     resizable;
@@ -135,6 +135,7 @@
     GLboolean     glDebug;
     int           glProfile;
     int           glRobustness;
+    _GLFWmonitor* monitor;
     _GLFWwindow*  share;
 };
 
@@ -183,6 +184,7 @@
     GLboolean visible;         // GL_TRUE if this window is visible
     int       refreshRate;     // monitor refresh rate
     void*     userPointer;
+    _GLFWmonitor* monitor;
 
     // Window input state
     GLboolean stickyKeys;
@@ -221,6 +223,30 @@
 
 
 //------------------------------------------------------------------------
+// Display structure
+//------------------------------------------------------------------------
+struct _GLFWmonitor
+{
+    void*     userPointer;
+
+    char*     name;
+
+    GLboolean primary;
+
+    // physical dimensions in millimeters.
+    int       physicalWidth;
+    int       physicalHeight;
+    // logical orientation of the screen on the desktop
+    int       positionX;
+    int       positionY;
+
+    GLFWvidmode*  modes;
+
+    // These are defined in the current port's platform.h
+    _GLFW_PLATFORM_MONITOR_STATE;
+};
+
+//------------------------------------------------------------------------
 // Library global data
 //------------------------------------------------------------------------
 struct _GLFWlibrary
@@ -230,13 +256,15 @@
     _GLFWwindow*  windowListHead;
     _GLFWwindow*  focusedWindow;
 
+    _GLFWmonitor** monitors;
+    int            monitorCount;
+    GLFWmonitorfun monitorCallback;
+
     GLFWgammaramp currentRamp;
     GLFWgammaramp originalRamp;
     int           originalRampSize;
     GLboolean     rampChanged;
 
-    GLFWvidmode*  modes;
-
     // This is defined in the current port's platform.h
     _GLFW_PLATFORM_LIBRARY_WINDOW_STATE;
     _GLFW_PLATFORM_LIBRARY_OPENGL_STATE;
@@ -269,9 +297,13 @@
 void _glfwPlatformSetCursorPos(_GLFWwindow* window, int x, int y);
 void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode);
 
+// Monitor support
+_GLFWmonitor** _glfwPlatformGetMonitors(int* count);
+void _glfwPlatformDestroyMonitor(_GLFWmonitor* monitor);
+
 // Video mode support
-GLFWvidmode* _glfwPlatformGetVideoModes(int* count);
-void _glfwPlatformGetDesktopMode(GLFWvidmode* mode);
+GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count);
+void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode);
 
 // Gamma ramp support
 void _glfwPlatformGetGammaRamp(GLFWgammaramp* ramp);
@@ -339,6 +371,9 @@
 void _glfwInputCursorMotion(_GLFWwindow* window, int x, int y);
 void _glfwInputCursorEnter(_GLFWwindow* window, int entered);
 
+// Monitor event notification (monitor.c)
+void _glfwInputMonitorChange(void);
+
 
 //========================================================================
 // Prototypes for internal utility functions
@@ -363,5 +398,12 @@
 GLboolean _glfwIsValidContextConfig(_GLFWwndconfig* wndconfig);
 GLboolean _glfwIsValidContext(_GLFWwndconfig* wndconfig);
 
+// Monitor management (monitor.c)
+_GLFWmonitor* _glfwCreateMonitor(const char* name,
+                                 GLboolean primary,
+                                 int physicalWidth, int physicalHeight,
+                                 int x, int y);
+void _glfwDestroyMonitor(_GLFWmonitor* monitor);
+void _glfwDestroyMonitors(void);
 
 #endif // _internal_h_
diff --git a/src/monitor.c b/src/monitor.c
new file mode 100644
index 0000000..0ae667f
--- /dev/null
+++ b/src/monitor.c
@@ -0,0 +1,432 @@
+//========================================================================
+// GLFW - An OpenGL framework
+// Platform:    Any
+// API version: 3.0
+// WWW:         http://www.glfw.org/
+//------------------------------------------------------------------------
+// Copyright (c) 2002-2006 Marcus Geelnard
+// Copyright (c) 2006-2010 Camilla Berglund <elmindreda@elmindreda.org>
+//
+// This software is provided 'as-is', without any express or implied
+// warranty. In no event will the authors be held liable for any damages
+// arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it
+// freely, subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented; you must not
+//    claim that you wrote the original software. If you use this software
+//    in a product, an acknowledgment in the product documentation would
+//    be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such, and must not
+//    be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source
+//    distribution.
+//
+//========================================================================
+
+#include "internal.h"
+
+#include <string.h>
+#include <stdlib.h>
+#if defined(_MSC_VER)
+ #include <malloc.h>
+ #define strdup _strdup
+#endif
+
+
+//========================================================================
+// Lexical comparison function for GLFW video modes, used by qsort
+//========================================================================
+
+static int compareVideoModes(const void* firstPtr, const void* secondPtr)
+{
+    int firstBPP, secondBPP, firstSize, secondSize;
+    GLFWvidmode* first = (GLFWvidmode*) firstPtr;
+    GLFWvidmode* second = (GLFWvidmode*) secondPtr;
+
+    // First sort on color bits per pixel
+
+    firstBPP = first->redBits +
+               first->greenBits +
+               first->blueBits;
+    secondBPP = second->redBits +
+                second->greenBits +
+                second->blueBits;
+
+    if (firstBPP != secondBPP)
+        return firstBPP - secondBPP;
+
+    // Then sort on screen area, in pixels
+
+    firstSize = first->width * first->height;
+    secondSize = second->width * second->height;
+
+    return firstSize - secondSize;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+//////                       GLFW internal API                      //////
+//////////////////////////////////////////////////////////////////////////
+
+//========================================================================
+// Create a monitor struct from the specified information
+//========================================================================
+
+_GLFWmonitor* _glfwCreateMonitor(const char* name,
+                                 GLboolean primary,
+                                 int physicalWidth, int physicalHeight,
+                                 int x, int y)
+{
+    _GLFWmonitor* monitor = (_GLFWmonitor*) calloc(1, sizeof(_GLFWmonitor));
+    if (!monitor)
+    {
+        _glfwSetError(GLFW_OUT_OF_MEMORY, NULL);
+        return NULL;
+    }
+
+    monitor->name = strdup(name);
+    monitor->primary = primary;
+    monitor->physicalWidth = physicalWidth;
+    monitor->physicalHeight = physicalHeight;
+    monitor->positionX = x;
+    monitor->positionY = y;
+
+    return monitor;
+}
+
+
+//========================================================================
+// Destroy the specified monitor
+//========================================================================
+
+void _glfwDestroyMonitor(_GLFWmonitor* monitor)
+{
+    if (monitor == NULL)
+        return;
+
+    _glfwPlatformDestroyMonitor(monitor);
+
+    free(monitor->modes);
+    free(monitor->name);
+    free(monitor);
+}
+
+
+//========================================================================
+// Enumerate monitors and notify user of changes
+//========================================================================
+
+void _glfwInputMonitorChange(void)
+{
+    int i, j, monitorCount;
+    _GLFWmonitor** monitors;
+
+    monitors = _glfwPlatformGetMonitors(&monitorCount);
+
+    for (i = 0;  i < monitorCount;  i++)
+    {
+        for (j = 0;  j < _glfwLibrary.monitorCount;  j++)
+        {
+            if (_glfwLibrary.monitors[j] == NULL)
+                continue;
+
+            if (strcmp(monitors[i]->name, _glfwLibrary.monitors[j]->name) == 0)
+            {
+                // This monitor was connected before, so re-use the existing
+                // monitor object to preserve its address and user pointer
+
+                _glfwDestroyMonitor(monitors[i]);
+                monitors[i] = _glfwLibrary.monitors[j];
+                _glfwLibrary.monitors[j] = NULL;
+                break;
+            }
+        }
+
+        if (j == _glfwLibrary.monitorCount)
+        {
+            // This monitor was not connected before
+            _glfwLibrary.monitorCallback(monitors[i], GLFW_CONNECTED);
+        }
+    }
+
+    for (i = 0;  i < _glfwLibrary.monitorCount;  i++)
+    {
+        _GLFWwindow* window;
+
+        if (_glfwLibrary.monitors[i] == NULL)
+            continue;
+
+        // This monitor is no longer connected
+        _glfwLibrary.monitorCallback(_glfwLibrary.monitors[i], GLFW_DISCONNECTED);
+
+        for (window = _glfwLibrary.windowListHead;  window;  window = window->next)
+        {
+            if (window->monitor == _glfwLibrary.monitors[i])
+                window->monitor = NULL;
+        }
+    }
+
+    _glfwDestroyMonitors();
+
+    _glfwLibrary.monitors = monitors;
+    _glfwLibrary.monitorCount = monitorCount;
+}
+
+
+//========================================================================
+// Destroy all monitors
+//========================================================================
+
+void _glfwDestroyMonitors(void)
+{
+    int i;
+
+    for (i = 0;  i < _glfwLibrary.monitorCount;  i++)
+        _glfwDestroyMonitor(_glfwLibrary.monitors[i]);
+
+    free(_glfwLibrary.monitors);
+    _glfwLibrary.monitors = NULL;
+    _glfwLibrary.monitorCount = 0;
+}
+
+
+//========================================================================
+// Lexical comparison of GLFW video modes
+//========================================================================
+
+int _glfwCompareVideoModes(const GLFWvidmode* first, const GLFWvidmode* second)
+{
+    return compareVideoModes(first, second);
+}
+
+
+//========================================================================
+// Convert BPP to RGB bits based on "best guess"
+//========================================================================
+
+void _glfwSplitBPP(int bpp, int* red, int* green, int* blue)
+{
+    int delta;
+
+    // We assume that by 32 the user really meant 24
+    if (bpp == 32)
+        bpp = 24;
+
+    // Convert "bits per pixel" to red, green & blue sizes
+
+    *red = *green = *blue = bpp / 3;
+    delta = bpp - (*red * 3);
+    if (delta >= 1)
+        *green = *green + 1;
+
+    if (delta == 2)
+        *red = *red + 1;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+//////                        GLFW public API                       //////
+//////////////////////////////////////////////////////////////////////////
+
+//========================================================================
+// Return the currently connected monitors
+//========================================================================
+
+GLFWAPI const GLFWmonitor* glfwGetMonitors(int* count)
+{
+    if (!_glfwInitialized)
+    {
+        _glfwSetError(GLFW_NOT_INITIALIZED, NULL);
+        return NULL;
+    }
+
+    if (count == NULL)
+    {
+        _glfwSetError(GLFW_INVALID_VALUE, NULL);
+        return NULL;
+    }
+
+    *count = _glfwLibrary.monitorCount;
+    return (GLFWmonitor*) _glfwLibrary.monitors;
+}
+
+
+//========================================================================
+// Get the primary monitor
+//========================================================================
+
+GLFWAPI GLFWmonitor glfwGetPrimaryMonitor(void)
+{
+    int i;
+    GLFWmonitor handle = NULL;
+
+    if (!_glfwInitialized)
+    {
+        _glfwSetError(GLFW_NOT_INITIALIZED, NULL);
+        return NULL;
+    }
+
+    for (i = 0;  i < _glfwLibrary.monitorCount;  i++)
+    {
+        if (_glfwLibrary.monitors[i]->primary)
+        {
+            handle = _glfwLibrary.monitors[i];
+            break;
+        }
+    }
+
+    if (!handle)
+    {
+        _glfwSetError(GLFW_PLATFORM_ERROR, NULL);
+        return NULL;
+    }
+
+    return handle;
+}
+
+
+//========================================================================
+// Get monitor parameter
+//========================================================================
+
+GLFWAPI int glfwGetMonitorParam(GLFWmonitor handle, int param)
+{
+    _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
+
+    if (!_glfwInitialized)
+    {
+        _glfwSetError(GLFW_NOT_INITIALIZED, NULL);
+        return 0;
+    }
+
+    if (monitor == NULL)
+    {
+        _glfwSetError(GLFW_INVALID_VALUE,
+                      "glfwGetMonitorParam: Invalid monitor handle");
+        return 0;
+    }
+
+    switch (param)
+    {
+        case GLFW_MONITOR_WIDTH_MM:
+            return monitor->physicalWidth;
+        case GLFW_MONITOR_HEIGHT_MM:
+            return monitor->physicalHeight;
+        case GLFW_MONITOR_POS_X:
+            return monitor->positionX;
+        case GLFW_MONITOR_POS_Y:
+            return monitor->positionY;
+    }
+
+    _glfwSetError(GLFW_INVALID_ENUM,
+                  "glfwGetMonitorParam: Invalid enum value for 'param' parameter");
+    return 0;
+}
+
+
+//========================================================================
+// Get monitor string
+//========================================================================
+
+GLFWAPI const char* glfwGetMonitorName(GLFWmonitor handle)
+{
+    _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
+
+    if (!_glfwInitialized)
+    {
+        _glfwSetError(GLFW_NOT_INITIALIZED, NULL);
+        return NULL;
+    }
+
+    if (monitor == NULL)
+    {
+        _glfwSetError(GLFW_INVALID_VALUE,
+                      "glfwGetMonitorString: Invalid monitor handle");
+        return NULL;
+    }
+
+    return monitor->name;
+}
+
+
+//========================================================================
+// Set a callback function for monitor events
+//========================================================================
+
+GLFWAPI void glfwSetMonitorCallback(GLFWmonitorfun cbfun)
+{
+    if (!_glfwInitialized)
+    {
+        _glfwSetError(GLFW_NOT_INITIALIZED, NULL);
+        return;
+    }
+
+    _glfwLibrary.monitorCallback= cbfun;
+}
+
+
+//========================================================================
+// Get a list of available video modes
+//========================================================================
+
+GLFWAPI const GLFWvidmode* glfwGetVideoModes(GLFWmonitor handle, int* count)
+{
+    _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
+
+    if (!_glfwInitialized)
+    {
+        _glfwSetError(GLFW_NOT_INITIALIZED, NULL);
+        return NULL;
+    }
+
+    if (monitor == NULL)
+    {
+        _glfwSetError(GLFW_INVALID_VALUE,
+                      "glfwGetVideoModes: Invalid monitor handle");
+        return 0;
+    }
+
+    if (count == NULL)
+    {
+        _glfwSetError(GLFW_INVALID_VALUE, NULL);
+        return NULL;
+    }
+
+    free(monitor->modes);
+
+    monitor->modes = _glfwPlatformGetVideoModes(monitor, count);
+    if (monitor->modes)
+        qsort(monitor->modes, *count, sizeof(GLFWvidmode), compareVideoModes);
+
+    return monitor->modes;
+}
+
+
+//========================================================================
+// Get the current video mode for the specified monitor
+//========================================================================
+
+GLFWAPI void glfwGetVideoMode(GLFWmonitor handle, GLFWvidmode* mode)
+{
+    _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
+
+    if (!_glfwInitialized)
+    {
+        _glfwSetError(GLFW_NOT_INITIALIZED, NULL);
+        return;
+    }
+
+    if (mode == NULL)
+    {
+        _glfwSetError(GLFW_INVALID_VALUE, NULL);
+        return;
+    }
+
+    _glfwPlatformGetVideoMode(monitor, mode);
+}
+
diff --git a/src/win32_fullscreen.c b/src/win32_monitor.c
similarity index 68%
rename from src/win32_fullscreen.c
rename to src/win32_monitor.c
index 26740d1..02b3a48 100644
--- a/src/win32_fullscreen.c
+++ b/src/win32_monitor.c
@@ -1,6 +1,6 @@
 //========================================================================
 // GLFW - An OpenGL library
-// Platform:    Win32
+// Platform:    X11 (Unix)
 // API version: 3.0
 // WWW:         http://www.glfw.org/
 //------------------------------------------------------------------------
@@ -31,9 +31,18 @@
 #include "internal.h"
 
 #include <stdlib.h>
+#include <string.h>
 #include <limits.h>
 #include <malloc.h>
 
+// These constants are missing on MinGW
+#ifndef EDS_ROTATEDMODE
+ #define EDS_ROTATEDMODE 0x00000004
+#endif
+#ifndef DISPLAY_DEVICE_ACTIVE
+ #define DISPLAY_DEVICE_ACTIVE 0x00000001
+#endif
+
 
 //========================================================================
 // Return closest video mode by dimensions, refresh rate and bits per pixel
@@ -180,12 +189,116 @@
 //////////////////////////////////////////////////////////////////////////
 
 //========================================================================
+// Return a list of available monitors
+//========================================================================
+
+_GLFWmonitor** _glfwPlatformGetMonitors(int* count)
+{
+    int size = 0, found = 0;
+    _GLFWmonitor** monitors = NULL;
+    DWORD adapterIndex = 0;
+
+    for (;;)
+    {
+        // Enumerate display adapters
+
+        DISPLAY_DEVICE adapter, monitor;
+        DEVMODE settings;
+        const char* name;
+        HDC dc;
+
+        ZeroMemory(&adapter, sizeof(DISPLAY_DEVICE));
+        adapter.cb = sizeof(DISPLAY_DEVICE);
+
+        if (!EnumDisplayDevices(NULL, adapterIndex, &adapter, 0))
+            break;
+
+        adapterIndex++;
+
+        if ((adapter.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER) ||
+            !(adapter.StateFlags & DISPLAY_DEVICE_ACTIVE))
+        {
+            continue;
+        }
+
+        ZeroMemory(&settings, sizeof(DEVMODE));
+        settings.dmSize = sizeof(DEVMODE);
+
+        EnumDisplaySettingsEx(adapter.DeviceName,
+                              ENUM_CURRENT_SETTINGS,
+                              &settings,
+                              EDS_ROTATEDMODE);
+
+        name = _glfwCreateUTF8FromWideString(adapter.DeviceName);
+        if (!name)
+        {
+            // TODO: wat
+            return NULL;
+        }
+
+        if (found == size)
+        {
+            if (size)
+                size *= 2;
+            else
+                size = 4;
+
+            monitors = (_GLFWmonitor**) realloc(monitors, sizeof(_GLFWmonitor*) * size);
+            if (!monitors)
+            {
+                // TODO: wat
+                return NULL;
+            }
+        }
+
+        ZeroMemory(&monitor, sizeof(DISPLAY_DEVICE));
+        monitor.cb = sizeof(DISPLAY_DEVICE);
+
+        EnumDisplayDevices(adapter.DeviceName, 0, &monitor, 0);
+        dc = CreateDC(L"DISPLAY", monitor.DeviceString, NULL, NULL);
+
+        const GLboolean primary = adapter.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE;
+
+        monitors[found] = _glfwCreateMonitor(name, primary,
+                                             GetDeviceCaps(dc, HORZSIZE),
+                                             GetDeviceCaps(dc, VERTSIZE),
+                                             settings.dmPosition.x,
+                                             settings.dmPosition.y);
+
+        DeleteDC(dc);
+
+        if (!monitors[found])
+        {
+            // TODO: wat
+            return NULL;
+        }
+
+        monitors[found]->Win32.name = _wcsdup(adapter.DeviceName);
+        found++;
+    }
+
+    *count = found;
+    return monitors;
+}
+
+
+//========================================================================
+// Destroy a monitor struct
+//========================================================================
+
+void _glfwPlatformDestroyMonitor(_GLFWmonitor* monitor)
+{
+    free(monitor->Win32.name);
+}
+
+
+//========================================================================
 // Get a list of available video modes
 //========================================================================
 
-GLFWvidmode* _glfwPlatformGetVideoModes(int* found)
+GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found)
 {
-    int dmIndex = 0, count = 0;
+    int modeIndex = 0, count = 0;
     GLFWvidmode* result = NULL;
 
     *found = 0;
@@ -199,10 +312,10 @@
         ZeroMemory(&dm, sizeof(DEVMODE));
         dm.dmSize = sizeof(DEVMODE);
 
-        if (!EnumDisplaySettings(NULL, dmIndex, &dm))
+        if (!EnumDisplaySettings(monitor->Win32.name, modeIndex, &dm))
             break;
 
-        dmIndex++;
+        modeIndex++;
 
         if (dm.dmBitsPerPel < 15)
         {
@@ -213,9 +326,9 @@
         mode.width = dm.dmPelsWidth;
         mode.height = dm.dmPelsHeight;
         _glfwSplitBPP(dm.dmBitsPerPel,
-                        &mode.redBits,
-                        &mode.greenBits,
-                        &mode.blueBits);
+                      &mode.redBits,
+                      &mode.greenBits,
+                      &mode.blueBits);
 
         for (i = 0;  i < *found;  i++)
         {
@@ -259,18 +372,18 @@
 
 
 //========================================================================
-// Get the desktop video mode
+// Get the current video mode for the specified monitor
 //========================================================================
 
-void _glfwPlatformGetDesktopMode(GLFWvidmode* mode)
+void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode)
 {
     DEVMODE dm;
 
-    // Get desktop display mode
+    ZeroMemory(&dm, sizeof(DEVMODE));
     dm.dmSize = sizeof(DEVMODE);
-    EnumDisplaySettings(NULL, ENUM_REGISTRY_SETTINGS, &dm);
 
-    // Return desktop mode parameters
+    EnumDisplaySettings(monitor->Win32.name, ENUM_REGISTRY_SETTINGS, &dm);
+
     mode->width  = dm.dmPelsWidth;
     mode->height = dm.dmPelsHeight;
     _glfwSplitBPP(dm.dmBitsPerPel,
diff --git a/src/win32_platform.h b/src/win32_platform.h
index 30d5534..4a6495a 100644
--- a/src/win32_platform.h
+++ b/src/win32_platform.h
@@ -62,6 +62,7 @@
 
 #include <windows.h>
 #include <mmsystem.h>
+#include <dbt.h>
 
 
 //========================================================================
@@ -117,6 +118,7 @@
 
 #define _GLFW_PLATFORM_WINDOW_STATE         _GLFWwindowWin32  Win32
 #define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryWin32 Win32
+#define _GLFW_PLATFORM_MONITOR_STATE        _GLFWmonitorWin32 Win32
 
 
 //========================================================================
@@ -190,6 +192,16 @@
 } _GLFWlibraryWin32;
 
 
+//------------------------------------------------------------------------
+// Platform-specific monitor structure
+//------------------------------------------------------------------------
+typedef struct _GLFWmonitorWin32
+{
+    WCHAR* name;
+
+} _GLFWmonitorWin32;
+
+
 //========================================================================
 // Prototypes for platform specific internal functions
 //========================================================================
diff --git a/src/win32_window.c b/src/win32_window.c
index a99f08d..3f2228c 100644
--- a/src/win32_window.c
+++ b/src/win32_window.c
@@ -30,7 +30,6 @@
 
 #include "internal.h"
 
-#include <stdio.h>
 #include <stdlib.h>
 #include <malloc.h>
 #include <windowsx.h>
@@ -348,7 +347,7 @@
                 if (window->cursorMode == GLFW_CURSOR_CAPTURED)
                     showCursor(window);
 
-                if (window->mode == GLFW_FULLSCREEN)
+                if (window->monitor)
                 {
                     if (!iconified)
                     {
@@ -371,7 +370,7 @@
                 if (window->cursorMode == GLFW_CURSOR_CAPTURED)
                     captureCursor(window);
 
-                if (window->mode == GLFW_FULLSCREEN)
+                if (window->monitor)
                 {
                     if (!_glfwLibrary.Win32.monitor.modeChanged)
                     {
@@ -404,7 +403,7 @@
                 case SC_SCREENSAVE:
                 case SC_MONITORPOWER:
                 {
-                    if (window->mode == GLFW_FULLSCREEN)
+                    if (window->monitor)
                     {
                         // We are running in fullscreen mode, so disallow
                         // screen saver and screen blanking
@@ -641,6 +640,16 @@
 
             break;
         }
+
+        case WM_DEVICECHANGE:
+        {
+            if (DBT_DEVNODES_CHANGED == wParam)
+            {
+                _glfwInputMonitorChange();
+                return TRUE;
+            }
+            break;
+        }
     }
 
     // Pass all unhandled messages to DefWindowProc
@@ -722,8 +731,7 @@
                         const _GLFWfbconfig* fbconfig)
 {
     DWORD dwStyle, dwExStyle;
-    int fullWidth, fullHeight;
-    RECT wa;
+    int positionX, positionY, fullWidth, fullHeight;
     POINT pos;
     WCHAR* wideTitle;
 
@@ -732,7 +740,7 @@
     dwExStyle = WS_EX_APPWINDOW;
 
     // Set window style, depending on fullscreen mode
-    if (window->mode == GLFW_FULLSCREEN)
+    if (window->monitor)
     {
         dwStyle |= WS_POPUP;
 
@@ -766,16 +774,21 @@
     // Adjust window size for frame and title bar
     getFullWindowSize(window, window->width, window->height, &fullWidth, &fullHeight);
 
-    // Adjust window position to working area (e.g. if the task bar is at
-    // the top of the display). Fullscreen windows are always opened in
-    // the upper left corner regardless of the desktop working area.
-    if (window->mode == GLFW_FULLSCREEN)
-        wa.left = wa.top = 0;
+    if (window->monitor)
+    {
+        // Fullscreen windows are always opened in the upper left corner
+        // regardless of the desktop working area
+        positionX = wndconfig->monitor->positionX;
+        positionY = wndconfig->monitor->positionY;
+    }
     else
     {
+        RECT wa;
         SystemParametersInfo(SPI_GETWORKAREA, 0, &wa, 0);
-        wa.left += wndconfig->positionX;
-        wa.top += wndconfig->positionY;
+
+        // Adjust window position to working area
+        positionX = wndconfig->positionX + wa.left;
+        positionY = wndconfig->positionY + wa.top;
     }
 
     wideTitle = _glfwCreateWideStringFromUTF8(wndconfig->title);
@@ -790,7 +803,7 @@
                                           _GLFW_WNDCLASSNAME,
                                           wideTitle,
                                           window->Win32.dwStyle,
-                                          wa.left, wa.top,       // Window position
+                                          positionX, positionY,
                                           fullWidth,             // Decorated window width
                                           fullHeight,            // Decorated window height
                                           NULL,                  // No parent window
@@ -864,7 +877,7 @@
             return GL_FALSE;
     }
 
-    if (window->mode == GLFW_FULLSCREEN)
+    if (window->monitor)
     {
         int bpp = fbconfig->redBits + fbconfig->greenBits + fbconfig->blueBits;
         if (bpp < 15 || bpp >= 24)
@@ -968,7 +981,7 @@
             return GL_FALSE;
     }
 
-    if (window->mode == GLFW_FULLSCREEN)
+    if (window->monitor)
     {
         // Place the window above all topmost windows
         _glfwPlatformShowWindow(window);
@@ -988,7 +1001,7 @@
 {
     destroyWindow(window);
 
-    if (window->mode == GLFW_FULLSCREEN)
+    if (window->monitor)
     {
         if (_glfwLibrary.Win32.monitor.modeChanged)
         {
@@ -1027,7 +1040,7 @@
 {
     GLboolean sizeChanged = GL_FALSE;
 
-    if (window->mode == GLFW_FULLSCREEN)
+    if (window->monitor)
     {
         if (width > window->width || height > window->height)
         {
@@ -1251,3 +1264,4 @@
     }
 }
 
+
diff --git a/src/window.c b/src/window.c
index f9048cb..3874837 100644
--- a/src/window.c
+++ b/src/window.c
@@ -206,7 +206,8 @@
 //========================================================================
 
 GLFWAPI GLFWwindow glfwCreateWindow(int width, int height,
-                                    int mode, const char* title,
+                                    const char* title,
+                                    GLFWmonitor monitor,
                                     GLFWwindow share)
 {
     _GLFWfbconfig fbconfig;
@@ -240,7 +241,6 @@
     fbconfig.sRGB           = _glfwLibrary.hints.sRGB ? GL_TRUE : GL_FALSE;
 
     // Set up desired window config
-    wndconfig.mode           = mode;
     wndconfig.title          = title;
     wndconfig.refreshRate    = Max(_glfwLibrary.hints.refreshRate, 0);
     wndconfig.resizable      = _glfwLibrary.hints.resizable ? GL_TRUE : GL_FALSE;
@@ -254,6 +254,7 @@
     wndconfig.glDebug        = _glfwLibrary.hints.glDebug ? GL_TRUE : GL_FALSE;
     wndconfig.glProfile      = _glfwLibrary.hints.glProfile;
     wndconfig.glRobustness   = _glfwLibrary.hints.glRobustness ? GL_TRUE : GL_FALSE;
+    wndconfig.monitor        = (_GLFWmonitor*) monitor;
     wndconfig.share          = (_GLFWwindow*) share;
 
     // Check the OpenGL bits of the window config
@@ -263,13 +264,6 @@
     // Save the currently current context so it can be restored later
     previous = glfwGetCurrentContext();
 
-    if (mode != GLFW_WINDOWED && mode != GLFW_FULLSCREEN)
-    {
-        _glfwSetError(GLFW_INVALID_ENUM,
-                      "glfwCreateWindow: Invalid window mode");
-        return GL_FALSE;
-    }
-
     if (width <= 0 || height <= 0)
     {
         _glfwSetError(GLFW_INVALID_VALUE,
@@ -290,9 +284,9 @@
     // Remember window settings
     window->width      = width;
     window->height     = height;
-    window->mode       = mode;
     window->resizable  = wndconfig.resizable;
     window->cursorMode = GLFW_CURSOR_NORMAL;
+    window->monitor    = (_GLFWmonitor*) monitor;
 
     // Open the actual window and create its context
     if (!_glfwPlatformCreateWindow(window, &wndconfig, &fbconfig))
@@ -333,10 +327,10 @@
 
     // The GLFW specification states that fullscreen windows have the cursor
     // captured by default
-    if (mode == GLFW_FULLSCREEN)
+    if (wndconfig.monitor)
         glfwSetInputMode(window, GLFW_CURSOR_MODE, GLFW_CURSOR_CAPTURED);
 
-    if (mode == GLFW_WINDOWED && wndconfig.visible)
+    if (wndconfig.monitor == NULL && wndconfig.visible)
         glfwShowWindow(window);
 
     return window;
@@ -587,7 +581,7 @@
 
     _glfwPlatformSetWindowSize(window, width, height);
 
-    if (window->mode == GLFW_FULLSCREEN)
+    if (window->monitor)
     {
         // Refresh window parameters (may have changed due to changed video
         // modes)
@@ -636,7 +630,7 @@
 
     _glfwPlatformRestoreWindow(window);
 
-    if (window->mode == GLFW_FULLSCREEN)
+    if (window->monitor)
         _glfwPlatformRefreshWindowParams(window);
 }
 
@@ -655,7 +649,7 @@
         return;
     }
 
-    if (window->mode == GLFW_FULLSCREEN)
+    if (window->monitor)
         return;
 
     _glfwPlatformShowWindow(window);
@@ -676,7 +670,7 @@
         return;
     }
 
-    if (window->mode == GLFW_FULLSCREEN)
+    if (window->monitor)
         return;
 
     _glfwPlatformHideWindow(window);
@@ -739,6 +733,24 @@
 
 
 //========================================================================
+// Get window monitor
+//========================================================================
+
+GLFWAPI GLFWmonitor glfwGetWindowMonitor(GLFWwindow handle)
+{
+    _GLFWwindow* window = (_GLFWwindow*) handle;
+
+    if (!_glfwInitialized)
+    {
+        _glfwSetError(GLFW_NOT_INITIALIZED, NULL);
+        return NULL;
+    }
+
+    return (GLFWmonitor) window->monitor;
+}
+
+
+//========================================================================
 // Set the user pointer for the specified window
 //========================================================================
 
diff --git a/src/x11_gamma.c b/src/x11_gamma.c
index 148ae74..f963b5a 100644
--- a/src/x11_gamma.c
+++ b/src/x11_gamma.c
@@ -59,9 +59,9 @@
 
         _glfwLibrary.originalRampSize = XRRGetCrtcGammaSize(_glfwLibrary.X11.display,
                                                             rr->crtcs[0]);
-        if (!_glfwLibrary.originalRampSize)
+        if (_glfwLibrary.originalRampSize == 0)
         {
-            // This is probably Nvidia RandR with broken gamma support
+            // This is probably older Nvidia RandR with broken gamma support
             // Flag it as useless and try Xf86VidMode below, if available
             _glfwLibrary.X11.RandR.gammaBroken = GL_TRUE;
         }
diff --git a/src/x11_fullscreen.c b/src/x11_monitor.c
similarity index 67%
rename from src/x11_fullscreen.c
rename to src/x11_monitor.c
index 9b1121f..e9e0a88 100644
--- a/src/x11_fullscreen.c
+++ b/src/x11_monitor.c
@@ -1,6 +1,6 @@
 //========================================================================
 // GLFW - An OpenGL library
-// Platform:    X11
+// Platform:    X11 (Unix)
 // API version: 3.0
 // WWW:         http://www.glfw.org/
 //------------------------------------------------------------------------
@@ -50,9 +50,8 @@
 // List available resolutions
 //========================================================================
 
-static _GLFWvidsize* getResolutions(int* found)
+static _GLFWvidsize* getResolutions(_GLFWmonitor* monitor, int* found)
 {
-    int i, j;
     _GLFWvidsize* result = NULL;
 
     *found = 0;
@@ -62,50 +61,42 @@
     if (_glfwLibrary.X11.RandR.available)
     {
 #if defined(_GLFW_HAS_XRANDR)
-        XRRScreenConfiguration* sc;
-        XRRScreenSize* sizes;
+        XRRScreenResources* sr;
+        int i, j, count = monitor->X11.output->nmode;
 
-        sc = XRRGetScreenInfo(_glfwLibrary.X11.display, _glfwLibrary.X11.root);
-        sizes = XRRConfigSizes(sc, found);
+        sr = XRRGetScreenResources(_glfwLibrary.X11.display,
+                                   _glfwLibrary.X11.root);
 
-        result = (_GLFWvidsize*) malloc(sizeof(_GLFWvidsize) * *found);
+        result = (_GLFWvidsize*) malloc(sizeof(_GLFWvidsize) * count);
 
-        for (i = 0;  i < *found;  i++)
-        {
-            result[i].width  = sizes[i].width;
-            result[i].height = sizes[i].height;
-        }
-
-        XRRFreeScreenConfigInfo(sc);
-#endif /*_GLFW_HAS_XRANDR*/
-    }
-    else if (_glfwLibrary.X11.VidMode.available)
-    {
-#if defined(_GLFW_HAS_XF86VIDMODE)
-        XF86VidModeModeInfo** modes;
-        int modeCount;
-
-        XF86VidModeGetAllModeLines(_glfwLibrary.X11.display,
-                                   _glfwLibrary.X11.screen,
-                                   &modeCount, &modes);
-
-        result = (_GLFWvidsize*) malloc(sizeof(_GLFWvidsize) * modeCount);
-
-        for (i = 0;  i < modeCount;  i++)
+        for (i = 0;  i < count;  i++)
         {
             _GLFWvidsize size;
-            size.width  = modes[i]->hdisplay;
-            size.height = modes[i]->vdisplay;
+
+            for (j = 0;  j < sr->nmode;  j++)
+            {
+                if (sr->modes[j].id == monitor->X11.output->modes[i])
+                    break;
+            }
+
+            if (j == sr->nmode)
+                continue;
+
+            size.width  = sr->modes[j].width;
+            size.height = sr->modes[j].height;
 
             for (j = 0;  j < *found;  j++)
             {
-                if (memcmp(result + j, &size, sizeof(_GLFWvidsize)) == 0)
+                if (result[j].width == size.width &&
+                    result[j].height == size.height)
+                {
                     break;
+                }
             }
 
             if (j < *found)
             {
-                // This size is a duplicate, so skip it
+                // This is a duplicate, so skip it
                 continue;
             }
 
@@ -113,8 +104,8 @@
             (*found)++;
         }
 
-        XFree(modes);
-#endif /*_GLFW_HAS_XF86VIDMODE*/
+        XRRFreeScreenResources(sr);
+#endif /*_GLFW_HAS_XRANDR*/
     }
 
     if (result == NULL)
@@ -207,46 +198,6 @@
             return bestsize;
 #endif /*_GLFW_HAS_XRANDR*/
     }
-    else if (_glfwLibrary.X11.VidMode.available)
-    {
-#if defined(_GLFW_HAS_XF86VIDMODE)
-        XF86VidModeModeInfo** modelist;
-        int bestmode, modecount;
-
-        // Get a list of all available display modes
-        XF86VidModeGetAllModeLines(_glfwLibrary.X11.display,
-                                   _glfwLibrary.X11.screen,
-                                   &modecount, &modelist);
-
-        // Find the best matching mode
-        bestmode  = -1;
-        bestmatch = INT_MAX;
-        for (i = 0;  i < modecount;  i++)
-        {
-            match = (*width - modelist[i]->hdisplay) *
-                    (*width - modelist[i]->hdisplay) +
-                    (*height - modelist[i]->vdisplay) *
-                    (*height - modelist[i]->vdisplay);
-            if (match < bestmatch)
-            {
-                bestmatch = match;
-                bestmode  = i;
-            }
-        }
-
-        if (bestmode != -1)
-        {
-            // Report width & height of best matching mode
-            *width = modelist[bestmode]->hdisplay;
-            *height = modelist[bestmode]->vdisplay;
-        }
-
-        XFree(modelist);
-
-        if (bestmode != -1)
-            return bestmode;
-#endif /*_GLFW_HAS_XF86VIDMODE*/
-    }
 
     // Default: Simply use the screen resolution
     *width = DisplayWidth(_glfwLibrary.X11.display, _glfwLibrary.X11.screen);
@@ -308,50 +259,6 @@
         XRRFreeScreenConfigInfo(sc);
 #endif /*_GLFW_HAS_XRANDR*/
     }
-    else if (_glfwLibrary.X11.VidMode.available)
-    {
-#if defined(_GLFW_HAS_XF86VIDMODE)
-        XF86VidModeModeInfo **modelist;
-        int modecount;
-
-        // Get a list of all available display modes
-        XF86VidModeGetAllModeLines(_glfwLibrary.X11.display,
-                                   _glfwLibrary.X11.screen,
-                                   &modecount, &modelist);
-
-        // Unlock mode switch if necessary
-        if (_glfwLibrary.X11.FS.modeChanged)
-        {
-            XF86VidModeLockModeSwitch(_glfwLibrary.X11.display,
-                                      _glfwLibrary.X11.screen,
-                                      0);
-        }
-
-        // Change the video mode to the desired mode
-        XF86VidModeSwitchToMode(_glfwLibrary.X11.display,
-                                _glfwLibrary.X11.screen,
-                                modelist[mode]);
-
-        // Set viewport to upper left corner (where our window will be)
-        XF86VidModeSetViewPort(_glfwLibrary.X11.display,
-                               _glfwLibrary.X11.screen,
-                               0, 0);
-
-        // Lock mode switch
-        XF86VidModeLockModeSwitch(_glfwLibrary.X11.display,
-                                  _glfwLibrary.X11.screen,
-                                  1);
-
-        // Remember old mode and flag that we have changed the mode
-        if (!_glfwLibrary.X11.FS.modeChanged)
-        {
-            _glfwLibrary.X11.FS.oldMode = *modelist[0];
-            _glfwLibrary.X11.FS.modeChanged = GL_TRUE;
-        }
-
-        XFree(modelist);
-#endif /*_GLFW_HAS_XF86VIDMODE*/
-    }
 }
 
 
@@ -400,20 +307,6 @@
             }
 #endif /*_GLFW_HAS_XRANDR*/
         }
-        else if (_glfwLibrary.X11.VidMode.available)
-        {
-#if defined(_GLFW_HAS_XF86VIDMODE)
-            // Unlock mode switch
-            XF86VidModeLockModeSwitch(_glfwLibrary.X11.display,
-                                      _glfwLibrary.X11.screen,
-                                      0);
-
-            // Change the video mode back to the old mode
-            XF86VidModeSwitchToMode(_glfwLibrary.X11.display,
-                                    _glfwLibrary.X11.screen,
-                                    &_glfwLibrary.X11.FS.oldMode);
-#endif /*_GLFW_HAS_XF86VIDMODE*/
-        }
 
         _glfwLibrary.X11.FS.modeChanged = GL_FALSE;
     }
@@ -426,10 +319,105 @@
 
 
 //========================================================================
+// Return a list of available monitors
+//========================================================================
+
+_GLFWmonitor** _glfwPlatformGetMonitors(int* count)
+{
+    int found = 0;
+    _GLFWmonitor** monitors = NULL;
+
+    if (_glfwLibrary.X11.RandR.available)
+    {
+#if defined (_GLFW_HAS_XRANDR)
+        int i;
+        XRRScreenResources* sr;
+
+        sr = XRRGetScreenResources(_glfwLibrary.X11.display,
+                                   _glfwLibrary.X11.root);
+
+        monitors = (_GLFWmonitor**) calloc(sr->noutput, sizeof(_GLFWmonitor*));
+        if (!monitors)
+        {
+            XRRFreeScreenResources(sr);
+
+            _glfwSetError(GLFW_OUT_OF_MEMORY, NULL);
+            return NULL;
+        }
+
+        for (i = 0;  i < sr->noutput;  i++)
+        {
+            XRROutputInfo* oi;
+            XRRCrtcInfo* ci;
+            int physicalWidth, physicalHeight;
+
+            oi = XRRGetOutputInfo(_glfwLibrary.X11.display, sr, sr->outputs[i]);
+            if (oi->connection != RR_Connected)
+            {
+                XRRFreeOutputInfo(oi);
+                continue;
+            }
+
+            if (oi->mm_width && oi->mm_height)
+            {
+                physicalWidth = oi->mm_width;
+                physicalHeight = oi->mm_height;
+            }
+            else
+            {
+                physicalWidth = DisplayWidthMM(_glfwLibrary.X11.display,
+                                               _glfwLibrary.X11.screen);
+                physicalHeight = DisplayHeightMM(_glfwLibrary.X11.display,
+                                                 _glfwLibrary.X11.screen);
+            }
+
+            ci = XRRGetCrtcInfo(_glfwLibrary.X11.display, sr, oi->crtc);
+
+            monitors[found] = _glfwCreateMonitor(oi->name,
+                                                 i == 0,
+                                                 physicalWidth, physicalHeight,
+                                                 ci->x, ci->y);
+
+            XRRFreeCrtcInfo(ci);
+
+            if (!monitors[found])
+            {
+                // TODO: wat
+                return NULL;
+            }
+
+            // This is retained until the monitor object is destroyed
+            monitors[found]->X11.output = oi;
+            found++;
+        }
+#endif /*_GLFW_HAS_XRANDR*/
+    }
+
+    *count = found;
+    return monitors;
+}
+
+
+//========================================================================
+// Destroy a monitor struct
+//========================================================================
+
+void _glfwPlatformDestroyMonitor(_GLFWmonitor* monitor)
+{
+    if (_glfwLibrary.X11.RandR.available)
+    {
+#if defined (_GLFW_HAS_XRANDR)
+        XRRFreeOutputInfo(monitor->X11.output);
+#endif /*_GLFW_HAS_XRANDR*/
+    }
+}
+
+
+//========================================================================
 // List available video modes
 //========================================================================
 
-GLFWvidmode* _glfwPlatformGetVideoModes(int* found)
+GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found)
 {
     XVisualInfo* visuals;
     XVisualInfo dummy;
@@ -488,7 +476,7 @@
 
     // Build all permutations of channel depths and resolutions
 
-    sizes = getResolutions(&sizeCount);
+    sizes = getResolutions(monitor, &sizeCount);
 
     result = (GLFWvidmode*) malloc(sizeof(GLFWvidmode) * rgbCount * sizeCount);
     *found = 0;
@@ -515,40 +503,54 @@
 
 
 //========================================================================
-// Get the desktop video mode
+// Get the current video mode for the specified monitor
 //========================================================================
 
-void _glfwPlatformGetDesktopMode(GLFWvidmode* mode)
+void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode)
 {
-    int bpp;
-
-    // Get and split display depth
-    bpp = DefaultDepth(_glfwLibrary.X11.display, _glfwLibrary.X11.screen);
-    _glfwSplitBPP(bpp, &mode->redBits, &mode->greenBits, &mode->blueBits);
-
-    if (_glfwLibrary.X11.FS.modeChanged)
+    if (_glfwLibrary.X11.RandR.available)
     {
-        if (_glfwLibrary.X11.RandR.available)
+#if defined (_GLFW_HAS_XRANDR)
+        XRRScreenResources* sr;
+        XRRCrtcInfo* ci;
+
+        sr = XRRGetScreenResources(_glfwLibrary.X11.display,
+                                   _glfwLibrary.X11.root);
+        if (!sr)
         {
-#if defined(_GLFW_HAS_XRANDR)
-            mode->width  = _glfwLibrary.X11.FS.oldWidth;
-            mode->height = _glfwLibrary.X11.FS.oldHeight;
+            _glfwSetError(GLFW_PLATFORM_ERROR,
+                          "X11: Failed to retrieve RandR screen resources");
+            return;
+        }
+
+        ci = XRRGetCrtcInfo(_glfwLibrary.X11.display,
+                            sr, monitor->X11.output->crtc);
+        if (!ci)
+        {
+            XRRFreeScreenResources(sr);
+
+            _glfwSetError(GLFW_PLATFORM_ERROR,
+                          "X11: Failed to retrieve RandR crtc info");
+            return;
+        }
+
+        mode->width = ci->width;
+        mode->height = ci->height;
+
+        XRRFreeCrtcInfo(ci);
+        XRRFreeScreenResources(sr);
 #endif /*_GLFW_HAS_XRANDR*/
-        }
-        else if (_glfwLibrary.X11.VidMode.available)
-        {
-#if defined(_GLFW_HAS_XF86VIDMODE)
-            mode->width  = _glfwLibrary.X11.FS.oldMode.hdisplay;
-            mode->height = _glfwLibrary.X11.FS.oldMode.vdisplay;
-#endif /*_GLFW_HAS_XF86VIDMODE*/
-        }
     }
     else
     {
         mode->width = DisplayWidth(_glfwLibrary.X11.display,
-                                   _glfwLibrary.X11.screen);
+                                _glfwLibrary.X11.screen);
         mode->height = DisplayHeight(_glfwLibrary.X11.display,
-                                     _glfwLibrary.X11.screen);
+                                    _glfwLibrary.X11.screen);
     }
+
+    _glfwSplitBPP(DefaultDepth(_glfwLibrary.X11.display,
+                               _glfwLibrary.X11.screen),
+                  &mode->redBits, &mode->greenBits, &mode->blueBits);
 }
 
diff --git a/src/x11_platform.h b/src/x11_platform.h
index 87c46d8..6e94cd5 100644
--- a/src/x11_platform.h
+++ b/src/x11_platform.h
@@ -67,6 +67,7 @@
 
 #define _GLFW_PLATFORM_WINDOW_STATE         _GLFWwindowX11  X11
 #define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryX11 X11
+#define _GLFW_PLATFORM_MONITOR_STATE        _GLFWmonitorX11 X11
 
 // Clipboard format atom indices
 #define _GLFW_CLIPBOARD_FORMAT_UTF8     0
@@ -217,6 +218,20 @@
 } _GLFWlibraryX11;
 
 
+//------------------------------------------------------------------------
+// Platform-specific monitor structure
+//------------------------------------------------------------------------
+typedef struct _GLFWmonitorX11
+{
+#if defined(_GLFW_HAS_XRANDR)
+    XRROutputInfo* output;
+#else
+    int dummy;
+#endif /*_GLFW_HAS_XRANDR*/
+
+} _GLFWmonitorX11;
+
+
 //========================================================================
 // Prototypes for platform specific internal functions
 //========================================================================
diff --git a/src/x11_window.c b/src/x11_window.c
index bc880d7..54436d2 100644
--- a/src/x11_window.c
+++ b/src/x11_window.c
@@ -103,11 +103,11 @@
         wa.colormap = window->X11.colormap;
         wa.border_pixel = 0;
         wa.event_mask = StructureNotifyMask | KeyPressMask | KeyReleaseMask |
-            PointerMotionMask | ButtonPressMask | ButtonReleaseMask |
-            ExposureMask | FocusChangeMask | VisibilityChangeMask |
-            EnterWindowMask | LeaveWindowMask;
+                        PointerMotionMask | ButtonPressMask | ButtonReleaseMask |
+                        ExposureMask | FocusChangeMask | VisibilityChangeMask |
+                        EnterWindowMask | LeaveWindowMask;
 
-        if (wndconfig->mode == GLFW_WINDOWED)
+        if (wndconfig->monitor == NULL)
         {
             // The /only/ reason for setting the background pixel here is that
             // otherwise our window won't get any decorations on systems using
@@ -144,7 +144,7 @@
         window->X11.positionY = wndconfig->positionY;
     }
 
-    if (window->mode == GLFW_FULLSCREEN && !_glfwLibrary.X11.hasEWMH)
+    if (window->monitor && !_glfwLibrary.X11.hasEWMH)
     {
         // This is the butcher's way of removing window decorations
         // Setting the override-redirect attribute on a window makes the window
@@ -221,6 +221,13 @@
 
         hints->flags = 0;
 
+        if (wndconfig->monitor)
+        {
+            hints->flags |= PPosition;
+            hints->x = wndconfig->monitor->positionX;
+            hints->y = wndconfig->monitor->positionY;
+        }
+
         if (!wndconfig->resizable)
         {
             hints->flags |= (PMinSize | PMaxSize);
@@ -247,7 +254,7 @@
     // Un-grab cursor (in windowed mode only; in fullscreen mode we still
     // want the cursor grabbed in order to confine the cursor to the window
     // area)
-    if (window->X11.cursorGrabbed && window->mode == GLFW_WINDOWED)
+    if (window->X11.cursorGrabbed && window->monitor == NULL)
     {
         XUngrabPointer(_glfwLibrary.X11.display, CurrentTime);
         window->X11.cursorGrabbed = GL_FALSE;
@@ -295,7 +302,7 @@
     // Un-grab cursor (in windowed mode only; in fullscreen mode we still
     // want the cursor grabbed in order to confine the cursor to the window
     // area)
-    if (window->X11.cursorGrabbed && window->mode == GLFW_WINDOWED)
+    if (window->X11.cursorGrabbed && window->monitor == NULL)
     {
         XUngrabPointer(_glfwLibrary.X11.display, CurrentTime);
         window->X11.cursorGrabbed = GL_FALSE;
@@ -825,6 +832,7 @@
                 case RRScreenChangeNotify:
                 {
                     XRRUpdateConfiguration(event);
+                    _glfwInputMonitorChange();
                     break;
                 }
             }
@@ -855,18 +863,18 @@
     if (!createWindow(window, wndconfig))
         return GL_FALSE;
 
-    if (wndconfig->mode == GLFW_FULLSCREEN)
-    {
 #if defined(_GLFW_HAS_XRANDR)
-        // Request screen change notifications
-        if (_glfwLibrary.X11.RandR.available)
-        {
-            XRRSelectInput(_glfwLibrary.X11.display,
-                           window->X11.handle,
-                           RRScreenChangeNotifyMask);
-        }
+    // Request screen change notifications
+    if (_glfwLibrary.X11.RandR.available)
+    {
+        XRRSelectInput(_glfwLibrary.X11.display,
+                       window->X11.handle,
+                       RRScreenChangeNotifyMask);
+    }
 #endif /*_GLFW_HAS_XRANDR*/
 
+    if (wndconfig->monitor)
+    {
         _glfwPlatformShowWindow(window);
         enterFullscreenMode(window);
     }
@@ -901,7 +909,7 @@
 
 void _glfwPlatformDestroyWindow(_GLFWwindow* window)
 {
-    if (window->mode == GLFW_FULLSCREEN)
+    if (window->monitor)
         leaveFullscreenMode(window);
 
     _glfwDestroyContext(window);
@@ -973,7 +981,7 @@
 
     rate = window->refreshRate;
 
-    if (window->mode == GLFW_FULLSCREEN)
+    if (window->monitor)
     {
         // Get the closest matching video mode for the specified window size
         mode = _glfwGetClosestVideoMode(&width, &height, &rate);
@@ -993,15 +1001,17 @@
         XFree(hints);
     }
 
-    // Change window size before changing fullscreen mode?
-    if (window->mode == GLFW_FULLSCREEN && (width > window->width))
+    if (window->monitor)
     {
-        XResizeWindow(_glfwLibrary.X11.display, window->X11.handle, width, height);
-        sizeChanged = GL_TRUE;
-    }
+        // Change window size before changing fullscreen mode?
+        if (width > window->width)
+        {
+            XResizeWindow(_glfwLibrary.X11.display,
+                          window->X11.handle,
+                          width, height);
+            sizeChanged = GL_TRUE;
+        }
 
-    if (window->mode == GLFW_FULLSCREEN)
-    {
         // Change video mode, keeping current refresh rate
         _glfwSetVideoModeMODE(mode, window->refreshRate);
     }
@@ -1096,22 +1106,6 @@
         XRRFreeScreenConfigInfo(sc);
 #endif /*_GLFW_HAS_XRANDR*/
     }
-    else if (_glfwLibrary.X11.VidMode.available)
-    {
-#if defined(_GLFW_HAS_XF86VIDMODE)
-        XF86VidModeModeLine modeline;
-        int dotclock;
-        float pixels_per_second, pixels_per_frame;
-
-        // Use the XF86VidMode extension to get current video mode
-        XF86VidModeGetModeLine(_glfwLibrary.X11.display,
-                               _glfwLibrary.X11.screen,
-                               &dotclock, &modeline);
-        pixels_per_second = 1000.0f * (float) dotclock;
-        pixels_per_frame  = (float) modeline.htotal * modeline.vtotal;
-        window->refreshRate = (int) (pixels_per_second / pixels_per_frame + 0.5);
-#endif /*_GLFW_HAS_XF86VIDMODE*/
-    }
     else
     {
         // Zero means unknown according to the GLFW spec
diff --git a/tests/accuracy.c b/tests/accuracy.c
index d320f64..e26d045 100644
--- a/tests/accuracy.c
+++ b/tests/accuracy.c
@@ -86,7 +86,7 @@
         exit(EXIT_FAILURE);
     }
 
-    window = glfwCreateWindow(window_width, window_height, GLFW_WINDOWED, "", NULL);
+    window = glfwCreateWindow(window_width, window_height, "", NULL, NULL);
     if (!window)
     {
         glfwTerminate();
diff --git a/tests/clipboard.c b/tests/clipboard.c
index c3746f1..b986174 100644
--- a/tests/clipboard.c
+++ b/tests/clipboard.c
@@ -125,7 +125,7 @@
         exit(EXIT_FAILURE);
     }
 
-    window = glfwCreateWindow(200, 200, GLFW_WINDOWED, "Clipboard Test", NULL);
+    window = glfwCreateWindow(200, 200, "Clipboard Test", NULL, NULL);
     if (!window)
     {
         glfwTerminate();
diff --git a/tests/defaults.c b/tests/defaults.c
index 8f08889..211071d 100644
--- a/tests/defaults.c
+++ b/tests/defaults.c
@@ -85,7 +85,7 @@
 
     glfwWindowHint(GLFW_VISIBLE, GL_FALSE);
 
-    window = glfwCreateWindow(640, 480, GLFW_WINDOWED, "Defaults", NULL);
+    window = glfwCreateWindow(640, 480, "Defaults", NULL, NULL);
     if (!window)
     {
         glfwTerminate();
diff --git a/tests/events.c b/tests/events.c
index 46bde2a..aca2e79 100644
--- a/tests/events.c
+++ b/tests/events.c
@@ -337,6 +337,32 @@
            get_character_string(character));
 }
 
+void monitor_callback(GLFWmonitor monitor, int event)
+{
+    if (event == GLFW_CONNECTED)
+    {
+        GLFWvidmode mode;
+        glfwGetVideoMode(monitor, &mode);
+
+        printf("%08x at %0.3f: Monitor %s (%ix%i at %ix%i, %ix%i mm) was connected\n",
+               counter++,
+               glfwGetTime(),
+               glfwGetMonitorName(monitor),
+               mode.width, mode.height,
+               glfwGetMonitorParam(monitor, GLFW_MONITOR_POS_X),
+               glfwGetMonitorParam(monitor, GLFW_MONITOR_POS_Y),
+               glfwGetMonitorParam(monitor, GLFW_MONITOR_WIDTH_MM),
+               glfwGetMonitorParam(monitor, GLFW_MONITOR_HEIGHT_MM));
+    }
+    else
+    {
+        printf("%08x at %0.3f: Monitor %s was disconnected\n",
+               counter++,
+               glfwGetTime(),
+               glfwGetMonitorName(monitor));
+    }
+}
+
 int main(void)
 {
     GLFWwindow window;
@@ -352,7 +378,7 @@
 
     printf("Library initialized\n");
 
-    window = glfwCreateWindow(640, 480, GLFW_WINDOWED, "Event Linter", NULL);
+    window = glfwCreateWindow(640, 480, "Event Linter", NULL, NULL);
     if (!window)
     {
         glfwTerminate();
@@ -363,6 +389,8 @@
 
     printf("Window opened\n");
 
+    glfwSetMonitorCallback(monitor_callback);
+
     glfwSetWindowPosCallback(window, window_pos_callback);
     glfwSetWindowSizeCallback(window, window_size_callback);
     glfwSetWindowCloseCallback(window, window_close_callback);
diff --git a/tests/fsaa.c b/tests/fsaa.c
index 735a1f5..a80f79e 100644
--- a/tests/fsaa.c
+++ b/tests/fsaa.c
@@ -95,7 +95,7 @@
 
     glfwWindowHint(GLFW_FSAA_SAMPLES, samples);
 
-    window = glfwCreateWindow(800, 400, GLFW_WINDOWED, "Aliasing Detector", NULL);
+    window = glfwCreateWindow(800, 400, "Aliasing Detector", NULL, NULL);
     if (!window)
     {
         glfwTerminate();
diff --git a/tests/fsfocus.c b/tests/fsfocus.c
index a87d136..5024ab7 100644
--- a/tests/fsfocus.c
+++ b/tests/fsfocus.c
@@ -82,7 +82,7 @@
         exit(EXIT_FAILURE);
     }
 
-    window = glfwCreateWindow(640, 480, GLFW_FULLSCREEN, "Fullscreen focus", NULL);
+    window = glfwCreateWindow(640, 480, "Fullscreen focus", glfwGetPrimaryMonitor(), NULL);
     if (!window)
     {
         glfwTerminate();
diff --git a/tests/gamma.c b/tests/gamma.c
index 8b995af..ebbe1ff 100644
--- a/tests/gamma.c
+++ b/tests/gamma.c
@@ -97,7 +97,7 @@
 int main(int argc, char** argv)
 {
     int width, height, ch;
-    int mode = GLFW_WINDOWED;
+    GLFWmonitor monitor = NULL;
     GLFWwindow window;
 
     while ((ch = getopt(argc, argv, "fh")) != -1)
@@ -109,7 +109,7 @@
                 exit(EXIT_SUCCESS);
 
             case 'f':
-                mode = GLFW_FULLSCREEN;
+                monitor = glfwGetPrimaryMonitor();
                 break;
 
             default:
@@ -124,12 +124,12 @@
         exit(EXIT_FAILURE);
     }
 
-    if (mode == GLFW_FULLSCREEN)
+    if (monitor)
     {
-        GLFWvidmode desktop_mode;
-        glfwGetDesktopMode(&desktop_mode);
-        width = desktop_mode.width;
-        height = desktop_mode.height;
+        GLFWvidmode mode;
+        glfwGetVideoMode(monitor, &mode);
+        width = mode.width;
+        height = mode.height;
     }
     else
     {
@@ -137,7 +137,7 @@
         height = 200;
     }
 
-    window = glfwCreateWindow(width, height, mode, "Gamma Test", NULL);
+    window = glfwCreateWindow(width, height, "Gamma Test", monitor, NULL);
     if (!window)
     {
         glfwTerminate();
diff --git a/tests/glfwinfo.c b/tests/glfwinfo.c
index 04a9d95..3ac0180 100644
--- a/tests/glfwinfo.c
+++ b/tests/glfwinfo.c
@@ -268,7 +268,7 @@
     // We assume here that we stand a better chance of success by leaving all
     // possible details of pixel format selection to GLFW
 
-    window = glfwCreateWindow(200, 200, GLFW_WINDOWED, "Version", NULL);
+    window = glfwCreateWindow(200, 200, "Version", NULL, NULL);
     if (!window)
     {
         glfwTerminate();
diff --git a/tests/iconify.c b/tests/iconify.c
index b0b6b6a..46c996e 100644
--- a/tests/iconify.c
+++ b/tests/iconify.c
@@ -92,9 +92,15 @@
 int main(int argc, char** argv)
 {
     int width, height, ch;
-    int mode = GLFW_WINDOWED;
+    GLFWmonitor monitor = NULL;
     GLFWwindow window;
 
+    if (!glfwInit())
+    {
+        fprintf(stderr, "Failed to initialize GLFW: %s\n", glfwErrorString(glfwGetError()));
+        exit(EXIT_FAILURE);
+    }
+
     while ((ch = getopt(argc, argv, "fh")) != -1)
     {
         switch (ch)
@@ -104,7 +110,7 @@
                 exit(EXIT_SUCCESS);
 
             case 'f':
-                mode = GLFW_FULLSCREEN;
+                monitor = glfwGetPrimaryMonitor();
                 break;
 
             default:
@@ -113,18 +119,12 @@
         }
     }
 
-    if (!glfwInit())
+    if (monitor)
     {
-        fprintf(stderr, "Failed to initialize GLFW: %s\n", glfwErrorString(glfwGetError()));
-        exit(EXIT_FAILURE);
-    }
-
-    if (mode == GLFW_FULLSCREEN)
-    {
-        GLFWvidmode desktop_mode;
-        glfwGetDesktopMode(&desktop_mode);
-        width = desktop_mode.width;
-        height = desktop_mode.height;
+        GLFWvidmode mode;
+        glfwGetVideoMode(monitor, &mode);
+        width = mode.width;
+        height = mode.height;
     }
     else
     {
@@ -132,7 +132,7 @@
         height = 480;
     }
 
-    window = glfwCreateWindow(width, height, mode, "Iconify", NULL);
+    window = glfwCreateWindow(width, height, "Iconify", monitor, NULL);
     if (!window)
     {
         glfwTerminate();
diff --git a/tests/joysticks.c b/tests/joysticks.c
index 2b24368..560dd20 100644
--- a/tests/joysticks.c
+++ b/tests/joysticks.c
@@ -191,7 +191,7 @@
         exit(EXIT_FAILURE);
     }
 
-    window = glfwCreateWindow(640, 480, GLFW_WINDOWED, "Joystick Test", NULL);
+    window = glfwCreateWindow(640, 480, "Joystick Test", NULL, NULL);
     if (!window)
     {
         glfwTerminate();
diff --git a/tests/modes.c b/tests/modes.c
index e1f13fa..8a260ea 100644
--- a/tests/modes.c
+++ b/tests/modes.c
@@ -49,7 +49,7 @@
     printf("       modes -h\n");
 }
 
-static const char* format_mode(GLFWvidmode* mode)
+static const char* format_mode(const GLFWvidmode* mode)
 {
     static char buffer[512];
 
@@ -90,46 +90,60 @@
     }
 }
 
-static void list_modes(void)
+static void list_modes(GLFWmonitor monitor)
 {
-    int count, i;
-    GLFWvidmode desktop_mode;
-    GLFWvidmode* modes = glfwGetVideoModes(&count);
+    int count, widthMM, heightMM, dpi, i;
+    GLFWvidmode mode;
+    const GLFWvidmode* modes = glfwGetVideoModes(monitor, &count);
 
-    glfwGetDesktopMode(&desktop_mode);
-    printf("Desktop mode: %s\n", format_mode(&desktop_mode));
+    glfwGetVideoMode(monitor, &mode);
 
-    printf("Available modes:\n");
+    printf("Name: %s\n", glfwGetMonitorName(monitor));
+    printf("Current mode: %s\n", format_mode(&mode));
+    printf("Virtual position: %i %i\n",
+           glfwGetMonitorParam(monitor, GLFW_MONITOR_POS_X),
+           glfwGetMonitorParam(monitor, GLFW_MONITOR_POS_Y));
+
+    widthMM = glfwGetMonitorParam(monitor, GLFW_MONITOR_WIDTH_MM);
+    heightMM = glfwGetMonitorParam(monitor, GLFW_MONITOR_HEIGHT_MM);
+    dpi = (int) ((float) mode.width * 25.4f / (float) widthMM);
+    printf("Physical size: %i x %i mm (%i dpi)\n", widthMM, heightMM, dpi);
+
+    printf("Modes:\n");
 
     for (i = 0;  i < count;  i++)
     {
         printf("%3u: %s", (unsigned int) i, format_mode(modes + i));
 
-        if (memcmp(&desktop_mode, modes + i, sizeof(GLFWvidmode)) == 0)
-            printf(" (desktop mode)");
+        if (memcmp(&mode, modes + i, sizeof(GLFWvidmode)) == 0)
+            printf(" (current mode)");
 
         putchar('\n');
     }
 }
 
-static void test_modes(void)
+static void test_modes(GLFWmonitor monitor)
 {
     int i, count;
-    GLFWvidmode* modes = glfwGetVideoModes(&count);
+    const GLFWvidmode* modes = glfwGetVideoModes(monitor, &count);
 
     for (i = 0;  i < count;  i++)
     {
-        GLFWvidmode* mode = modes + i;
+        const GLFWvidmode* mode = modes + i;
         GLFWvidmode current;
 
         glfwWindowHint(GLFW_RED_BITS, mode->redBits);
         glfwWindowHint(GLFW_GREEN_BITS, mode->greenBits);
         glfwWindowHint(GLFW_BLUE_BITS, mode->blueBits);
 
-        printf("Testing mode %u: %s", (unsigned int) i, format_mode(mode));
+        printf("Testing mode %u on monitor %s: %s\n",
+               (unsigned int) i,
+               glfwGetMonitorName(monitor),
+               format_mode(mode));
 
         window_handle = glfwCreateWindow(mode->width, mode->height,
-                                         GLFW_FULLSCREEN, "Video Mode Test",
+                                         "Video Mode Test",
+                                         glfwGetPrimaryMonitor(),
                                          NULL);
         if (!window_handle)
         {
@@ -195,7 +209,8 @@
 
 int main(int argc, char** argv)
 {
-    int ch, mode = LIST_MODE;
+    int ch, i, count, mode = LIST_MODE;
+    const GLFWmonitor* monitors;
 
     while ((ch = getopt(argc, argv, "th")) != -1)
     {
@@ -221,10 +236,15 @@
     if (!glfwInit())
         exit(EXIT_FAILURE);
 
-    if (mode == LIST_MODE)
-        list_modes();
-    else if (mode == TEST_MODE)
-        test_modes();
+    monitors = glfwGetMonitors(&count);
+
+    for (i = 0;  i < count;  i++)
+    {
+        if (mode == LIST_MODE)
+            list_modes(monitors[i]);
+        else if (mode == TEST_MODE)
+            test_modes(monitors[i]);
+    }
 
     glfwTerminate();
     exit(EXIT_SUCCESS);
diff --git a/tests/peter.c b/tests/peter.c
index 30690e6..5a294ee 100644
--- a/tests/peter.c
+++ b/tests/peter.c
@@ -92,7 +92,7 @@
 
 static GLboolean open_window(void)
 {
-    window_handle = glfwCreateWindow(640, 480, GLFW_WINDOWED, "Peter Detector", NULL);
+    window_handle = glfwCreateWindow(640, 480, "Peter Detector", NULL, NULL);
     if (!window_handle)
         return GL_FALSE;
 
diff --git a/tests/reopen.c b/tests/reopen.c
index 212c108..5097b65 100644
--- a/tests/reopen.c
+++ b/tests/reopen.c
@@ -41,19 +41,6 @@
 static GLFWwindow window_handle = NULL;
 static GLboolean closed = GL_FALSE;
 
-static const char* get_mode_name(int mode)
-{
-    switch (mode)
-    {
-        case GLFW_WINDOWED:
-            return "windowed";
-        case GLFW_FULLSCREEN:
-            return "fullscreen";
-        default:
-            return "unknown";
-    }
-}
-
 static void window_size_callback(GLFWwindow window, int width, int height)
 {
     glViewport(0, 0, width, height);
@@ -80,22 +67,18 @@
     }
 }
 
-static GLboolean open_window(int width, int height, int mode)
+static GLboolean open_window(int width, int height, GLFWmonitor monitor)
 {
     double base;
 
-    if (!glfwInit())
-    {
-        fprintf(stderr, "Failed to initialize GLFW: %s\n", glfwErrorString(glfwGetError()));
-        return GL_FALSE;
-    }
-
     base = glfwGetTime();
 
-    window_handle = glfwCreateWindow(width, height, mode, "Window Re-opener", NULL);
+    window_handle = glfwCreateWindow(width, height, "Window Re-opener", monitor, NULL);
     if (!window_handle)
     {
-        fprintf(stderr, "Failed to open %s mode GLFW window: %s\n", get_mode_name(mode), glfwErrorString(glfwGetError()));
+        fprintf(stderr, "Failed to open %s mode GLFW window: %s\n",
+                monitor ? "fullscreen" : "windowed",
+                glfwErrorString(glfwGetError()));
         return GL_FALSE;
     }
 
@@ -107,7 +90,7 @@
     glfwSetKeyCallback(window_handle, key_callback);
 
     printf("Opening %s mode window took %0.3f seconds\n",
-           get_mode_name(mode),
+           monitor ? "fullscreen" : "windowed",
            glfwGetTime() - base);
 
     return GL_TRUE;
@@ -121,17 +104,26 @@
     window_handle = NULL;
 
     printf("Closing window took %0.3f seconds\n", glfwGetTime() - base);
-
-    glfwTerminate();
 }
 
 int main(int argc, char** argv)
 {
     int count = 0;
 
+    if (!glfwInit())
+    {
+        fprintf(stderr, "Failed to initialize GLFW: %s\n", glfwErrorString(glfwGetError()));
+        return GL_FALSE;
+    }
+
     for (;;)
     {
-        if (!open_window(640, 480, (count & 1) ? GLFW_FULLSCREEN : GLFW_WINDOWED))
+        GLFWmonitor monitor = NULL;
+
+        if (count & 1)
+            monitor = glfwGetPrimaryMonitor();
+
+        if (!open_window(640, 480, monitor))
         {
             glfwTerminate();
             exit(EXIT_FAILURE);
diff --git a/tests/sharing.c b/tests/sharing.c
index 0042a85..69c4c4c 100644
--- a/tests/sharing.c
+++ b/tests/sharing.c
@@ -57,7 +57,7 @@
 
     glfwWindowHint(GLFW_POSITION_X, posX);
     glfwWindowHint(GLFW_POSITION_Y, posY);
-    window = glfwCreateWindow(WIDTH, HEIGHT, GLFW_WINDOWED, title, share);
+    window = glfwCreateWindow(WIDTH, HEIGHT, title, NULL, share);
     if (!window)
         return NULL;
 
diff --git a/tests/tearing.c b/tests/tearing.c
index 63ece2b..881d7b5 100644
--- a/tests/tearing.c
+++ b/tests/tearing.c
@@ -70,7 +70,7 @@
         exit(EXIT_FAILURE);
     }
 
-    window = glfwCreateWindow(640, 480, GLFW_WINDOWED, "", NULL);
+    window = glfwCreateWindow(640, 480, "", NULL, NULL);
     if (!window)
     {
         fprintf(stderr, "Failed to open GLFW window: %s\n", glfwErrorString(glfwGetError()));
diff --git a/tests/threads.c b/tests/threads.c
index 8b06b1d..27cb7b0 100644
--- a/tests/threads.c
+++ b/tests/threads.c
@@ -92,9 +92,8 @@
         glfwWindowHint(GLFW_POSITION_X, 200 + 250 * i);
         glfwWindowHint(GLFW_POSITION_Y, 200);
         threads[i].window = glfwCreateWindow(200, 200,
-                                             GLFW_WINDOWED,
                                              threads[i].title,
-                                             NULL);
+                                             NULL, NULL);
         if (!threads[i].window)
         {
             fprintf(stderr, "Failed to open GLFW window: %s\n",
diff --git a/tests/title.c b/tests/title.c
index 62690f9..f7e216a 100644
--- a/tests/title.c
+++ b/tests/title.c
@@ -47,7 +47,7 @@
         exit(EXIT_FAILURE);
     }
 
-    window = glfwCreateWindow(400, 400, GLFW_WINDOWED, "English 日本語 русский язык 官話", NULL);
+    window = glfwCreateWindow(400, 400, "English 日本語 русский язык 官話", NULL, NULL);
     if (!window)
     {
         fprintf(stderr, "Failed to open GLFW window: %s\n", glfwErrorString(glfwGetError()));
diff --git a/tests/windows.c b/tests/windows.c
index 187248c..dc2eec7 100644
--- a/tests/windows.c
+++ b/tests/windows.c
@@ -57,7 +57,7 @@
     {
         glfwWindowHint(GLFW_POSITION_X, 100 + (i & 1) * 300);
         glfwWindowHint(GLFW_POSITION_Y, 100 + (i >> 1) * 300);
-        windows[i] = glfwCreateWindow(200, 200, GLFW_WINDOWED, titles[i], NULL);
+        windows[i] = glfwCreateWindow(200, 200, titles[i], NULL, NULL);
         if (!windows[i])
         {
             fprintf(stderr, "Failed to open GLFW window: %s\n",