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);
}