Merge branch 'master' into multi-monitor

Conflicts:
	tests/modes.c
diff --git a/.gitignore b/.gitignore
index 0496a03..ff40c17 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,26 +1,30 @@
+.DS_Store
+CMakeCache.txt
 CMakeFiles
 cmake_install.cmake
-CMakeCache.txt
-Makefile
 cmake_uninstall.cmake
-.DS_Store
 docs/Doxyfile
-src/config.h
-src/libglfw.pc
-src/libglfw.so
-src/libglfw.a
-src/libglfw.dylib
-src/glfw.lib
-src/glfw.dll
-src/glfwdll.lib
+examples/*.app
+examples/*.exe
 examples/boing
 examples/gears
 examples/heightmap
 examples/splitview
 examples/triangle
 examples/wave
-examples/*.app
-examples/*.exe
+src/config.h
+src/glfw.dll
+src/glfw.lib
+src/glfwdll.lib
+src/libglfw.a
+src/libglfw.dll
+src/libglfw.dylib
+src/libglfw.lib
+src/libglfw.pc
+src/libglfw.so
+src/libglfwdll.lib
+tests/*.app
+tests/*.exe
 tests/accuracy
 tests/defaults
 tests/dynamic
@@ -31,12 +35,10 @@
 tests/glfwinfo
 tests/iconify
 tests/joysticks
-tests/listmodes
 tests/peter
 tests/reopen
 tests/sharing
 tests/tearing
 tests/title
+tests/version
 tests/windows
-tests/*.app
-tests/*.exe
diff --git a/include/GL/glfw3.h b/include/GL/glfw3.h
index 050f0c3..c3f2a2c 100644
--- a/include/GL/glfw3.h
+++ b/include/GL/glfw3.h
@@ -462,10 +462,22 @@
 /* Gamma ramps */
 #define GLFW_GAMMA_RAMP_SIZE      256
 
+/* Monitor constants */
+#define GLFW_MONITOR_NAME            0x00060000
+#define GLFW_MONITOR_PHYSICAL_WIDTH  0x00060001
+#define GLFW_MONITOR_PHYSICAL_HEIGHT 0x00060002
+#define GLFW_MONITOR_SCREEN_POS_X    0x00060003
+#define GLFW_MONITOR_SCREEN_POS_Y    0x00060004
+#define GLFW_MONITOR_CONNECTED       0x00061000
+#define GLFW_MONITOR_DISCONNECTED    0x00061001
+
 /*************************************************************************
  * Typedefs
  *************************************************************************/
 
+/* Monitor handle type */
+typedef void* GLFWmonitor;
+
 /* OpenGL function pointer type */
 typedef void (*GLFWglproc)(void);
 
@@ -485,6 +497,7 @@
 typedef void (* GLFWscrollfun)(GLFWwindow,double,double);
 typedef void (* GLFWkeyfun)(GLFWwindow,int,int);
 typedef void (* GLFWcharfun)(GLFWwindow,int);
+typedef void (* GLFWmonitordevicefun)(GLFWmonitor,int);
 
 /* The video mode structure used by glfwGetVideoModes */
 typedef struct
@@ -520,8 +533,20 @@
 GLFWAPI const char* glfwErrorString(int error);
 GLFWAPI void glfwSetErrorCallback(GLFWerrorfun cbfun);
 
+/* Monitor callback registration */
+GLFWAPI void glfwSetMonitorDeviceCallback(GLFWmonitordevicefun cbfun);
+
+/* Monitor attributes */
+GLFWAPI void glfwSetMonitorUserPointer(GLFWmonitor monitor, void* pointer);
+GLFWAPI void* glfwGetMonitorUserPointer(GLFWmonitor monitor);
+GLFWAPI int glfwGetMonitorParam(GLFWmonitor monitor, int param);
+GLFWAPI const char* glfwGetMonitorString(GLFWmonitor monitor, int param);
+
+/* Monitor discovery */
+GLFWAPI GLFWmonitor glfwGetNextMonitor(GLFWmonitor iterator);
+
 /* Video mode functions */
-GLFWAPI GLFWvidmode* glfwGetVideoModes(int* count);
+GLFWAPI GLFWvidmode* glfwGetVideoModes(GLFWmonitor monitor, int* count);
 GLFWAPI void glfwGetDesktopMode(GLFWvidmode* mode);
 
 /* Gamma ramp functions */
diff --git a/readme.html b/readme.html
index 39d0739..0ef6875 100644
--- a/readme.html
+++ b/readme.html
@@ -915,6 +915,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 f204a63..27fdf20 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -4,7 +4,7 @@
 
 set(common_HEADERS ${GLFW_SOURCE_DIR}/include/GL/glfw3.h internal.h)
 set(common_SOURCES clipboard.c error.c fullscreen.c gamma.c init.c input.c
-                   joystick.c opengl.c time.c window.c)
+                   joystick.c monitor.c opengl.c time.c window.c)
 
 if (_GLFW_COCOA_NSGL)
     set(glfw_HEADERS ${common_HEADERS} cocoa_platform.h)
@@ -18,14 +18,14 @@
     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_input.c win32_joystick.c
-                     win32_native.c win32_opengl.c win32_time.c win32_window.c
-                     win32_dllmain.c)
+                     win32_monitor.c win32_native.c win32_opengl.c win32_time.c
+                     win32_window.c win32_dllmain.c)
 elseif (_GLFW_X11_GLX)
     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_input.c x11_joystick.c
-                     x11_keysym2unicode.c x11_native.c x11_opengl.c x11_time.c
-                     x11_window.c)
+                     x11_keysym2unicode.c x11_monitor.c x11_native.c
+                     x11_opengl.c x11_time.c x11_window.c)
 endif()
 
 add_library(glfw ${glfw_SOURCES} ${glfw_HEADERS})
diff --git a/src/fullscreen.c b/src/fullscreen.c
index 9dab1a5..05b94d7 100644
--- a/src/fullscreen.c
+++ b/src/fullscreen.c
@@ -38,7 +38,7 @@
 // Lexical comparison function for GLFW video modes, used by qsort
 //========================================================================
 
-static int compareVideoModes(const void* firstPtr, const void* secondPtr)
+int compareVideoModes(const void* firstPtr, const void* secondPtr)
 {
     int firstBPP, secondBPP, firstSize, secondSize;
     GLFWvidmode* first = (GLFWvidmode*) firstPtr;
@@ -111,27 +111,36 @@
 // Get a list of available video modes
 //========================================================================
 
-GLFWAPI GLFWvidmode* glfwGetVideoModes(int* count)
+GLFWAPI 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(_glfwLibrary.modes);
+    free(monitor->modes);
 
-    _glfwLibrary.modes = _glfwPlatformGetVideoModes(count);
-    if (_glfwLibrary.modes)
-        qsort(_glfwLibrary.modes, *count, sizeof(GLFWvidmode), compareVideoModes);
+    monitor->modes = _glfwPlatformGetVideoModes(monitor, count);
+    if (monitor->modes)
+        qsort(monitor->modes, *count, sizeof(GLFWvidmode), compareVideoModes);
 
-    return _glfwLibrary.modes;
+    return monitor->modes;
 }
 
 
diff --git a/src/init.c b/src/init.c
index e1d5dfc..f59a4f5 100644
--- a/src/init.c
+++ b/src/init.c
@@ -84,9 +84,6 @@
     if (!_glfwPlatformTerminate())
         return;
 
-    if (_glfwLibrary.modes)
-        free(_glfwLibrary.modes);
-
     _glfwInitialized = GL_FALSE;
 }
 
diff --git a/src/internal.h b/src/internal.h
old mode 100644
new mode 100755
index 89ac48b..74a9130
--- a/src/internal.h
+++ b/src/internal.h
@@ -60,6 +60,7 @@
 typedef struct _GLFWfbconfig    _GLFWfbconfig;
 typedef struct _GLFWwindow      _GLFWwindow;
 typedef struct _GLFWlibrary     _GLFWlibrary;
+typedef struct _GLFWmonitor     _GLFWmonitor;
 
 
 //------------------------------------------------------------------------
@@ -209,6 +210,29 @@
 
 
 //------------------------------------------------------------------------
+// Display structure
+//------------------------------------------------------------------------
+struct _GLFWmonitor
+{
+    struct _GLFWmonitor* next;
+
+    void*     userPointer;
+
+    char*     name;
+    // physical dimensions in millimeters.
+    int       physicalWidth;
+    int       physicalHeight;
+    // logical orientation of the screen on the desktop
+    int       screenX;
+    int       screenY;
+
+    GLFWvidmode*  modes;
+
+    // These are defined in the current port's platform.h
+    _GLFW_PLATFORM_MONITOR_STATE;
+};
+
+//------------------------------------------------------------------------
 // Library global data
 //------------------------------------------------------------------------
 struct _GLFWlibrary
@@ -218,6 +242,8 @@
     _GLFWwindow*  windowListHead;
     _GLFWwindow*  currentWindow;
     _GLFWwindow*  activeWindow;
+    _GLFWwindow*  cursorLockWindow;
+    _GLFWmonitor* monitorListHead;
 
     GLFWwindowsizefun    windowSizeCallback;
     GLFWwindowclosefun   windowCloseCallback;
@@ -230,14 +256,13 @@
     GLFWscrollfun        scrollCallback;
     GLFWkeyfun           keyCallback;
     GLFWcharfun          charCallback;
+    GLFWmonitordevicefun 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;
@@ -274,7 +299,7 @@
 void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode);
 
 // Fullscreen
-GLFWvidmode* _glfwPlatformGetVideoModes(int* count);
+GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count);
 void _glfwPlatformGetDesktopMode(GLFWvidmode* mode);
 
 // Gamma ramp
@@ -356,5 +381,9 @@
 GLboolean _glfwIsValidContextConfig(_GLFWwndconfig* wndconfig);
 GLboolean _glfwIsValidContext(_GLFWwndconfig* wndconfig);
 
+// Monitor management (monitor.c)
+void _glfwInitMonitors(void);
+void _glfwRefreshMonitors(void);
+void _glfwTerminateMonitors(void);
 
 #endif // _internal_h_
diff --git a/src/monitor.c b/src/monitor.c
new file mode 100644
index 0000000..d30b7c3
--- /dev/null
+++ b/src/monitor.c
@@ -0,0 +1,256 @@
+//========================================================================
+// 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>
+
+
+//////////////////////////////////////////////////////////////////////////
+//////                        GLFW public API                       //////
+//////////////////////////////////////////////////////////////////////////
+
+//========================================================================
+// Iterate through connected monitors
+//========================================================================
+
+GLFWAPI GLFWmonitor glfwGetNextMonitor(GLFWmonitor handle)
+{
+    _GLFWmonitor* iterator = (_GLFWmonitor*) handle;
+    _GLFWmonitor* result = NULL;
+
+    if (!_glfwInitialized)
+    {
+        _glfwSetError(GLFW_NOT_INITIALIZED, NULL);
+        return result;
+    }
+
+    if (iterator == NULL)
+        result = _glfwLibrary.monitorListHead;
+    else
+        result = iterator->next;
+
+    return result;
+}
+
+
+//========================================================================
+// 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_PHYSICAL_WIDTH:
+            return monitor->physicalWidth;
+        case GLFW_MONITOR_PHYSICAL_HEIGHT:
+            return monitor->physicalHeight;
+        case GLFW_MONITOR_SCREEN_POS_X:
+            return monitor->screenX;
+        case GLFW_MONITOR_SCREEN_POS_Y:
+            return monitor->screenY;
+    }
+
+    _glfwSetError(GLFW_INVALID_ENUM,
+                  "glfwGetMonitorParam: Invalid enum value for 'param' parameter");
+    return 0;
+}
+
+
+//========================================================================
+// Get monitor string
+//========================================================================
+
+GLFWAPI const char* glfwGetMonitorString(GLFWmonitor handle, int param)
+{
+    _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;
+    }
+
+    switch (param)
+    {
+        case GLFW_MONITOR_NAME:
+            return monitor->name;
+    }
+
+    _glfwSetError(GLFW_INVALID_ENUM,
+                  "glfwGetMonitorString: Invalid enum value for 'param' parameter");
+    return NULL;
+}
+
+
+//========================================================================
+// Set a callback function for monitor events
+//========================================================================
+
+GLFWAPI void glfwSetMonitorDeviceCallback(GLFWmonitordevicefun cbfun)
+{
+    if (!_glfwInitialized)
+    {
+        _glfwSetError(GLFW_NOT_INITIALIZED, NULL);
+        return;
+    }
+
+    _glfwLibrary.monitorCallback= cbfun;
+}
+
+
+//========================================================================
+// Initialize the monitor list.
+//========================================================================
+
+void _glfwInitMonitors(void)
+{
+    _glfwLibrary.monitorListHead = _glfwCreateMonitors();
+}
+
+
+//========================================================================
+// Refresh monitor list and notify callback.
+//========================================================================
+
+void _glfwRefreshMonitors(void)
+{
+    _GLFWmonitor* newMonitorList;
+    _GLFWmonitor* curNewMonitor;
+    _GLFWmonitor* curOldMonitor;
+
+    newMonitorList = _glfwCreateMonitors();
+    curNewMonitor = newMonitorList;
+    curOldMonitor = _glfwLibrary.monitorListHead;
+
+    while (_glfwLibrary.monitorCallback && (curNewMonitor || curOldMonitor))
+    {
+        _GLFWmonitor* lookAheadOldMonitor;
+        _GLFWmonitor* lookAheadNewMonitor;
+
+        if (curOldMonitor && curNewMonitor && !strcmp(curOldMonitor->name, curOldMonitor->name))
+        {
+            curNewMonitor = curNewMonitor->next;
+            curOldMonitor = curOldMonitor->next;
+            continue;
+        }
+
+        if (curNewMonitor && !curOldMonitor)
+        {
+            _glfwLibrary.monitorCallback(curNewMonitor, GLFW_MONITOR_CONNECTED);
+            curNewMonitor = curNewMonitor->next;
+            continue;
+        }
+
+        if (!curNewMonitor && curOldMonitor)
+        {
+            _glfwLibrary.monitorCallback(curOldMonitor, GLFW_MONITOR_DISCONNECTED);
+            curOldMonitor = curOldMonitor->next;
+            continue;
+        }
+
+        lookAheadOldMonitor = curOldMonitor->next;
+        lookAheadNewMonitor = curNewMonitor->next;
+
+        while (lookAheadOldMonitor && !strcmp(curNewMonitor->name, lookAheadOldMonitor->name))
+            lookAheadOldMonitor = lookAheadOldMonitor->next;
+
+        while (lookAheadNewMonitor && !strcmp(curOldMonitor->name, lookAheadNewMonitor->name))
+            lookAheadNewMonitor = lookAheadNewMonitor->next;
+
+        if (!lookAheadOldMonitor)
+        {
+            // nothing found in the old monitor list, that matches the current new monitor.
+            _glfwLibrary.monitorCallback(curNewMonitor, GLFW_MONITOR_CONNECTED);
+            curNewMonitor = curNewMonitor->next;
+        }
+        else
+        {
+            while (strcmp(curOldMonitor->name, lookAheadOldMonitor->name))
+            {
+                _glfwLibrary.monitorCallback(curOldMonitor, GLFW_MONITOR_DISCONNECTED);
+                curOldMonitor = curOldMonitor->next;
+            }
+        }
+
+        if (!lookAheadNewMonitor)
+        {
+            // nothing found in the new monitor list, that matches the current old monitor.
+            _glfwLibrary.monitorCallback(curOldMonitor, GLFW_MONITOR_DISCONNECTED);
+            curOldMonitor = curOldMonitor->next;
+        }
+        else
+        {
+            while (strcmp(curNewMonitor->name, lookAheadNewMonitor->name))
+            {
+                _glfwLibrary.monitorCallback(curNewMonitor, GLFW_MONITOR_CONNECTED);
+                curNewMonitor = curNewMonitor->next;
+            }
+        }
+    }
+
+    _glfwTerminateMonitors();
+    _glfwLibrary.monitorListHead = newMonitorList;
+}
+
+
+//========================================================================
+// Delete the monitor list.
+//========================================================================
+
+void _glfwTerminateMonitors(void)
+{
+    while (_glfwLibrary.monitorListHead)
+        _glfwLibrary.monitorListHead = _glfwDestroyMonitor(_glfwLibrary.monitorListHead);
+}
+
diff --git a/src/win32_fullscreen.c b/src/win32_fullscreen.c
index 3e28e30..cbb0bb7 100644
--- a/src/win32_fullscreen.c
+++ b/src/win32_fullscreen.c
@@ -183,10 +183,18 @@
 // Get a list of available video modes
 //========================================================================
 
-GLFWvidmode* _glfwPlatformGetVideoModes(int* found)
+GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found)
 {
-    int dmIndex = 0, count = 0;
+    int deviceModeIndex = 0, count = 0;
     GLFWvidmode* result = NULL;
+    WCHAR* deviceName;
+
+    deviceName = _glfwCreateWideStringFromUTF8(monitor->Win32.name);
+    if (!deviceName)
+    {
+        _glfwSetError(GLFW_PLATFORM_ERROR, "Win32: Failed to convert device name");
+        return NULL;
+    }
 
     *found = 0;
 
@@ -199,10 +207,10 @@
         ZeroMemory(&dm, sizeof(DEVMODE));
         dm.dmSize = sizeof(DEVMODE);
 
-        if (!EnumDisplaySettings(NULL, dmIndex, &dm))
+        if (!EnumDisplaySettings(deviceName, deviceModeIndex, &dm))
             break;
 
-        dmIndex++;
+        deviceModeIndex++;
 
         if (dm.dmBitsPerPel < 15)
         {
@@ -254,6 +262,7 @@
         (*found)++;
     }
 
+    free(deviceName);
     return result;
 }
 
diff --git a/src/win32_init.c b/src/win32_init.c
index 41444b9..a9c7b7a 100644
--- a/src/win32_init.c
+++ b/src/win32_init.c
@@ -178,6 +178,8 @@
     _glfwPlatformGetGammaRamp(&_glfwLibrary.originalRamp);
     _glfwLibrary.currentRamp = _glfwLibrary.originalRamp;
 
+    _glfwInitMonitors();
+
     _glfwInitTimer();
 
     return GL_TRUE;
@@ -194,6 +196,8 @@
     if (_glfwLibrary.rampChanged)
         _glfwPlatformSetGammaRamp(&_glfwLibrary.originalRamp);
 
+    _glfwTerminateMonitors();
+
     if (_glfwLibrary.Win32.classAtom)
     {
         UnregisterClass(_GLFW_WNDCLASSNAME, _glfwLibrary.Win32.instance);
diff --git a/src/win32_monitor.c b/src/win32_monitor.c
new file mode 100644
index 0000000..2aba1ff
--- /dev/null
+++ b/src/win32_monitor.c
@@ -0,0 +1,138 @@
+//========================================================================
+// GLFW - An OpenGL library
+// Platform:    X11 (Unix)
+// 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 <stdlib.h>
+#include <string.h>
+
+// The MinGW package for Debian lacks this
+#ifndef EDS_ROTATEDMODE
+#define EDS_ROTATEDMODE 0x00000004
+#endif
+
+// The MinGW upstream lacks this
+#ifndef DISPLAY_DEVICE_ACTIVE
+#define DISPLAY_DEVICE_ACTIVE 0x00000001
+#endif
+
+
+//////////////////////////////////////////////////////////////////////////
+//////                       GLFW platform API                      //////
+//////////////////////////////////////////////////////////////////////////
+
+//========================================================================
+// Create a monitor struct from the specified information
+//========================================================================
+
+_GLFWmonitor** _glfwCreateMonitor(_GLFWmonitor** current,
+                                  DISPLAY_DEVICE* adapter,
+                                  DISPLAY_DEVICE* monitor,
+                                  DEVMODE* setting)
+{
+    HDC dc = NULL;
+
+    *current = malloc(sizeof(_GLFWmonitor));
+    memset(*current, 0, sizeof(_GLFWmonitor));
+
+    dc = CreateDC(L"DISPLAY", monitor->DeviceString, NULL, NULL);
+
+    (*current)->physicalWidth  = GetDeviceCaps(dc, HORZSIZE);
+    (*current)->physicalHeight = GetDeviceCaps(dc, VERTSIZE);
+
+    DeleteDC(dc);
+
+    (*current)->name = _glfwCreateUTF8FromWideString(monitor->DeviceName);
+
+    (*current)->screenX = setting->dmPosition.x;
+    (*current)->screenY = setting->dmPosition.y;
+
+    (*current)->Win32.name = _glfwCreateUTF8FromWideString(adapter->DeviceName);
+
+    return &((*current)->next);
+}
+
+
+//========================================================================
+// Destroy a monitor struct
+//========================================================================
+
+_GLFWmonitor* _glfwDestroyMonitor(_GLFWmonitor* monitor)
+{
+    _GLFWmonitor* result;
+
+    result = monitor->next;
+
+    free(monitor->Win32.name);
+    free(monitor->name);
+    free(monitor);
+
+    return result;
+}
+
+
+//========================================================================
+// Return a list of available monitors
+//========================================================================
+
+_GLFWmonitor* _glfwCreateMonitors(void)
+{
+    DISPLAY_DEVICE adapter;
+    DWORD adapterNum;
+    DISPLAY_DEVICE monitor;
+    DEVMODE setting;
+    _GLFWmonitor* monitorList;
+    _GLFWmonitor** curMonitor;
+
+    adapter.cb = sizeof(DISPLAY_DEVICE);
+    adapterNum = 0;
+    monitor.cb = sizeof(DISPLAY_DEVICE);
+    setting.dmSize = sizeof(DEVMODE);
+    monitorList = NULL;
+    curMonitor = &monitorList;
+
+    while (EnumDisplayDevices(NULL, adapterNum++, &adapter, 0))
+    {
+        if (adapter.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER || !(adapter.StateFlags & DISPLAY_DEVICE_ACTIVE))
+            continue;
+
+        EnumDisplaySettingsEx(adapter.DeviceName,
+                              ENUM_CURRENT_SETTINGS,
+                              &setting,
+                              EDS_ROTATEDMODE);
+
+        EnumDisplayDevices(adapter.DeviceName, 0, &monitor, 0);
+
+        curMonitor = _glfwCreateMonitor(curMonitor, &adapter, &monitor, &setting);
+    }
+
+    return monitorList;
+}
+
diff --git a/src/win32_platform.h b/src/win32_platform.h
index 79bbbb9..c0c2e15 100644
--- a/src/win32_platform.h
+++ b/src/win32_platform.h
@@ -62,6 +62,7 @@
 
 #include <windows.h>
 #include <mmsystem.h>
+#include <dbt.h>
 
 // This path may need to be changed if you build GLFW using your own setup
 // We ship and use our own copy of wglext.h since GLFW uses fairly new
@@ -112,6 +113,9 @@
 
 #define _GLFW_PLATFORM_WINDOW_STATE  _GLFWwindowWin32 Win32
 #define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextWGL WGL
+
+#define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorWin32 Win32
+
 #define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryWin32 Win32
 #define _GLFW_PLATFORM_LIBRARY_OPENGL_STATE _GLFWlibraryWGL WGL
 
@@ -210,6 +214,14 @@
 
 } _GLFWlibraryWin32;
 
+//------------------------------------------------------------------------
+// Platform-specific monitor structure
+//------------------------------------------------------------------------
+typedef struct _GLFWmonitorWin32
+{
+    char* name;
+
+} _GLFWmonitorWin32;
 
 //------------------------------------------------------------------------
 // Platform-specific library global data for WGL
@@ -232,6 +244,10 @@
 // Time
 void _glfwInitTimer(void);
 
+// Monitor support
+_GLFWmonitor* _glfwCreateMonitors(void);
+_GLFWmonitor* _glfwDestroyMonitor(_GLFWmonitor* monitor);
+
 // OpenGL support
 int _glfwCreateContext(_GLFWwindow* window,
                        const _GLFWwndconfig* wndconfig,
diff --git a/src/win32_window.c b/src/win32_window.c
index 77b9902..846c263 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>
 
@@ -749,6 +748,16 @@
 
             break;
         }
+
+        case WM_DEVICECHANGE:
+        {
+            if (DBT_DEVNODES_CHANGED == wParam)
+            {
+                _glfwRefreshMonitors();
+                return TRUE;
+            }
+            break;
+        }
     }
 
     // Pass all unhandled messages to DefWindowProc
@@ -1349,3 +1358,4 @@
     }
 }
 
+
diff --git a/src/x11_fullscreen.c b/src/x11_fullscreen.c
index 8c4138d..cc0736a 100644
--- a/src/x11_fullscreen.c
+++ b/src/x11_fullscreen.c
@@ -50,7 +50,7 @@
 // List available resolutions
 //========================================================================
 
-static _GLFWvidsize* getResolutions(int* found)
+static _GLFWvidsize* getResolutions(_GLFWmonitor* monitor, int* found)
 {
     int i, j;
     _GLFWvidsize* result = NULL;
@@ -424,12 +424,11 @@
 //////                       GLFW platform API                      //////
 //////////////////////////////////////////////////////////////////////////
 
-
 //========================================================================
 // List available video modes
 //========================================================================
 
-GLFWvidmode* _glfwPlatformGetVideoModes(int* found)
+GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found)
 {
     XVisualInfo* visuals;
     XVisualInfo dummy;
@@ -488,7 +487,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;
diff --git a/src/x11_init.c b/src/x11_init.c
index 372fc2d..654e9fc 100644
--- a/src/x11_init.c
+++ b/src/x11_init.c
@@ -648,6 +648,8 @@
 
     _glfwInitJoysticks();
 
+    _glfwInitMonitors();
+
     // Start the timer
     _glfwInitTimer();
 
@@ -671,6 +673,8 @@
 
     terminateDisplay();
 
+    _glfwTerminateMonitors();
+
     _glfwTerminateJoysticks();
 
     _glfwTerminateOpenGL();
diff --git a/src/x11_monitor.c b/src/x11_monitor.c
new file mode 100644
index 0000000..e36bbdc
--- /dev/null
+++ b/src/x11_monitor.c
@@ -0,0 +1,144 @@
+//========================================================================
+// GLFW - An OpenGL library
+// Platform:    X11 (Unix)
+// 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 <stdlib.h>
+#include <string.h>
+
+
+//////////////////////////////////////////////////////////////////////////
+//////                       GLFW platform API                      //////
+//////////////////////////////////////////////////////////////////////////
+
+//========================================================================
+// Create a monitor struct from the specified information
+//========================================================================
+
+#if defined (_GLFW_HAS_XRANDR)
+_GLFWmonitor** _glfwCreateMonitor(_GLFWmonitor** current,
+                                  XRROutputInfo* outputInfo,
+                                  XRRCrtcInfo* crtcInfo)
+{
+    *current = malloc(sizeof(_GLFWmonitor));
+    memset(*current, 0, sizeof(_GLFWmonitor));
+
+    (*current)->physicalWidth  = outputInfo->mm_width;
+    (*current)->physicalHeight = outputInfo->mm_height;
+
+    (*current)->name = strdup(outputInfo->name);
+
+    (*current)->screenX = crtcInfo->x;
+    (*current)->screenY = crtcInfo->y;
+
+    (*current)->X11.output = outputInfo;
+    return &((*current)->next);
+}
+#endif /*_GLFW_HAS_XRANDR*/
+
+
+//========================================================================
+// Destroy a monitor struct
+//========================================================================
+
+_GLFWmonitor* _glfwDestroyMonitor(_GLFWmonitor* monitor)
+{
+    _GLFWmonitor* result;
+
+    result = monitor->next;
+
+#if defined (_GLFW_HAS_XRANDR)
+    XRRFreeOutputInfo(monitor->X11.output);
+#endif /*_GLFW_HAS_XRANDR*/
+
+    free(monitor->modes);
+    free(monitor->name);
+    free(monitor);
+
+    return result;
+}
+
+
+//========================================================================
+// Return a list of available monitors
+//========================================================================
+
+_GLFWmonitor* _glfwCreateMonitors(void)
+{
+    _GLFWmonitor* monitorList = NULL;
+
+    if (_glfwLibrary.X11.RandR.available)
+    {
+#if defined (_GLFW_HAS_XRANDR)
+        int oi;
+        XRRScreenResources* resources;
+        _GLFWmonitor** monitor = &monitorList;
+
+        resources = XRRGetScreenResources(_glfwLibrary.X11.display,
+                                          _glfwLibrary.X11.root);
+
+        for (oi = 0;  oi < resources->noutput;  oi++)
+        {
+            // physical device
+            XRROutputInfo* outputInfo = NULL;
+            // logical surface
+            XRRCrtcInfo* crtcInfo = NULL;
+
+            outputInfo = XRRGetOutputInfo(_glfwLibrary.X11.display,
+                                          resources,
+                                          resources->outputs[oi]);
+
+            if (outputInfo->connection == RR_Connected)
+            {
+                int ci;
+
+                for (ci = 0;  ci < outputInfo->ncrtc;  ci++)
+                {
+                    if (outputInfo->crtc == outputInfo->crtcs[ci])
+                    {
+                        crtcInfo = XRRGetCrtcInfo(_glfwLibrary.X11.display,
+                                                  resources,
+                                                  outputInfo->crtcs[ci]);
+                        break;
+                    }
+                }
+
+                monitor = _glfwCreateMonitor(monitor, outputInfo, crtcInfo);
+
+                // Freeing of the outputInfo is done in _glfwDestroyMonitor
+                XRRFreeCrtcInfo(crtcInfo);
+            }
+        }
+#endif /*_GLFW_HAS_XRANDR*/
+    }
+
+    return monitorList;
+}
+
diff --git a/src/x11_platform.h b/src/x11_platform.h
index 3959365..c70c7d5 100644
--- a/src/x11_platform.h
+++ b/src/x11_platform.h
@@ -83,6 +83,9 @@
 
 #define _GLFW_PLATFORM_WINDOW_STATE  _GLFWwindowX11 X11
 #define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextGLX GLX
+
+#define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorX11 X11
+
 #define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryX11 X11
 #define _GLFW_PLATFORM_LIBRARY_OPENGL_STATE _GLFWlibraryGLX GLX
 
@@ -281,6 +284,20 @@
 } _glfwJoy[GLFW_JOYSTICK_LAST + 1];
 
 
+//------------------------------------------------------------------------
+// Platform-specific window 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
 //========================================================================
@@ -311,6 +328,10 @@
 void _glfwInitJoysticks(void);
 void _glfwTerminateJoysticks(void);
 
+// Monitors
+_GLFWmonitor* _glfwCreateMonitors(void);
+_GLFWmonitor* _glfwDestroyMonitor(_GLFWmonitor* monitor);
+
 // Unicode support
 long _glfwKeySym2Unicode(KeySym keysym);
 
diff --git a/src/x11_window.c b/src/x11_window.c
index 442e76c..0787882 100644
--- a/src/x11_window.c
+++ b/src/x11_window.c
@@ -866,6 +866,7 @@
                 {
                     // Show XRandR that we really care
                     XRRUpdateConfiguration(&event);
+                    _glfwRefreshMonitors();
                     break;
                 }
             }
@@ -896,18 +897,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->mode == GLFW_FULLSCREEN)
+    {
         enterFullscreenMode(window);
     }
 
diff --git a/tests/events.c b/tests/events.c
index f82b8fc..c7a4649 100644
--- a/tests/events.c
+++ b/tests/events.c
@@ -220,6 +220,19 @@
     return result;
 }
 
+static const char* get_monitor_event_name(int event)
+{
+    switch (event)
+    {
+        case GLFW_MONITOR_CONNECTED:
+            return "connected";
+        case GLFW_MONITOR_DISCONNECTED:
+            return "disconnected";
+    }
+
+    return NULL;
+}
+
 static void window_size_callback(GLFWwindow window, int width, int height)
 {
     printf("%08x at %0.3f: Window size: %i %i\n",
@@ -345,6 +358,16 @@
            get_character_string(character));
 }
 
+void monitor_callback(GLFWmonitor monitor, int event)
+{
+    printf("%08x at %0.3f: Monitor %s %s\n",
+           counter++,
+           glfwGetTime(),
+           glfwGetMonitorString(monitor, GLFW_MONITOR_NAME),
+           get_monitor_event_name(event));
+
+}
+
 int main(void)
 {
     GLFWwindow window;
@@ -371,6 +394,7 @@
     glfwSetScrollCallback(scroll_callback);
     glfwSetKeyCallback(key_callback);
     glfwSetCharCallback(char_callback);
+    glfwSetMonitorDeviceCallback(monitor_callback);
 
     window = glfwCreateWindow(0, 0, GLFW_WINDOWED, "Event Linter", NULL);
     if (!window)
diff --git a/tests/modes.c b/tests/modes.c
old mode 100644
new mode 100755
index 5ce65ab..8a51726
--- a/tests/modes.c
+++ b/tests/modes.c
@@ -90,16 +90,19 @@
     }
 }
 
-static void list_modes(void)
+static void list_modes(GLFWmonitor monitor)
 {
     int count, i;
     GLFWvidmode desktop_mode;
-    GLFWvidmode* modes = glfwGetVideoModes(&count);
+    GLFWvidmode* modes = glfwGetVideoModes(monitor, &count);
 
     glfwGetDesktopMode(&desktop_mode);
     printf("Desktop mode: %s\n", format_mode(&desktop_mode));
 
-    printf("Available modes:\n");
+    printf("Monitor %s (%ix%i mm):\n",
+           glfwGetMonitorString(monitor, GLFW_MONITOR_NAME),
+           glfwGetMonitorParam(monitor, GLFW_MONITOR_PHYSICAL_WIDTH),
+           glfwGetMonitorParam(monitor, GLFW_MONITOR_PHYSICAL_HEIGHT));
 
     for (i = 0;  i < count;  i++)
     {
@@ -112,10 +115,10 @@
     }
 }
 
-static void test_modes(void)
+static void test_modes(GLFWmonitor monitor)
 {
     int i, count;
-    GLFWvidmode* modes = glfwGetVideoModes(&count);
+    GLFWvidmode* modes = glfwGetVideoModes(monitor, &count);
 
     glfwSetWindowSizeCallback(window_size_callback);
     glfwSetWindowCloseCallback(window_close_callback);
@@ -130,7 +133,10 @@
         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,
+               glfwGetMonitorString(monitor, GLFW_MONITOR_NAME),
+               format_mode(mode));
 
         window = glfwCreateWindow(mode->width, mode->height,
                                   GLFW_FULLSCREEN, "Video Mode Test",
@@ -194,6 +200,7 @@
 int main(int argc, char** argv)
 {
     int ch, mode = LIST_MODE;
+    GLFWmonitor monitor = NULL;
 
     while ((ch = getopt(argc, argv, "th")) != -1)
     {
@@ -219,10 +226,13 @@
     if (!glfwInit())
         exit(EXIT_FAILURE);
 
-    if (mode == LIST_MODE)
-        list_modes();
-    else if (mode == TEST_MODE)
-        test_modes();
+    while ((monitor = glfwGetNextMonitor(monitor)))
+    {
+        if (mode == LIST_MODE)
+            list_modes(monitor);
+        else if (mode == TEST_MODE)
+            test_modes(monitor);
+    }
 
     exit(EXIT_SUCCESS);
 }