Merge branch 'master' into multi-monitor Conflicts: include/GL/glfw3.h src/CMakeLists.txt src/fullscreen.c src/internal.h src/win32_fullscreen.c src/win32_platform.h src/x11_fullscreen.c 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 7a47f86..6811d9b 100644 --- a/include/GL/glfw3.h +++ b/include/GL/glfw3.h
@@ -459,10 +459,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); @@ -482,6 +494,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 @@ -517,8 +530,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 12f73f3..f399f75 100644 --- a/readme.html +++ b/readme.html
@@ -913,6 +913,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 926ef66..7822c56 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt
@@ -5,7 +5,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) @@ -19,14 +19,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 d613ab7..08ac957 100644 --- a/src/fullscreen.c +++ b/src/fullscreen.c
@@ -37,7 +37,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; @@ -110,27 +110,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 eab5869..336cfe2 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 99d74b8..66f413b --- 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; //------------------------------------------------------------------------ @@ -224,6 +225,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 @@ -233,6 +257,8 @@ _GLFWwindow* windowListHead; _GLFWwindow* currentWindow; _GLFWwindow* activeWindow; + _GLFWwindow* cursorLockWindow; + _GLFWmonitor* monitorListHead; GLFWwindowsizefun windowSizeCallback; GLFWwindowclosefun windowCloseCallback; @@ -245,14 +271,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; @@ -289,7 +314,7 @@ void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode); // Fullscreen -GLFWvidmode* _glfwPlatformGetVideoModes(int* count); +GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count); void _glfwPlatformGetDesktopMode(GLFWvidmode* mode); // Gamma ramp @@ -370,5 +395,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 c04e5ff..b6edb54 100644 --- a/src/win32_fullscreen.c +++ b/src/win32_fullscreen.c
@@ -182,10 +182,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; @@ -198,10 +206,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) { @@ -253,6 +261,7 @@ (*found)++; } + free(deviceName); return result; }
diff --git a/src/win32_init.c b/src/win32_init.c index 5bcbb31..6865851 100644 --- a/src/win32_init.c +++ b/src/win32_init.c
@@ -177,6 +177,8 @@ _glfwPlatformGetGammaRamp(&_glfwLibrary.originalRamp); _glfwLibrary.currentRamp = _glfwLibrary.originalRamp; + _glfwInitMonitors(); + _glfwInitTimer(); return GL_TRUE; @@ -193,6 +195,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 fff50ea..85846bd 100755 --- a/src/win32_window.c +++ b/src/win32_window.c
@@ -30,7 +30,6 @@ #include "internal.h" -#include <stdio.h> #include <stdlib.h> @@ -749,6 +748,16 @@ break; } + + case WM_DEVICECHANGE: + { + if (DBT_DEVNODES_CHANGED == wParam) + { + _glfwRefreshMonitors(); + return TRUE; + } + break; + } } // Pass all unhandled messages to DefWindowProc @@ -1351,3 +1360,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 e5c548d..1bf2da7 100644 --- a/src/x11_window.c +++ b/src/x11_window.c
@@ -878,6 +878,7 @@ { // Show XRandR that we really care XRRUpdateConfiguration(&event); + _glfwRefreshMonitors(); break; } } @@ -927,18 +928,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 8ab5426..4e85c08 100644 --- a/tests/events.c +++ b/tests/events.c
@@ -217,6 +217,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", @@ -341,6 +354,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; @@ -366,6 +389,7 @@ glfwSetScrollCallback(scroll_callback); glfwSetKeyCallback(key_callback); glfwSetCharCallback(char_callback); + glfwSetMonitorDeviceCallback(monitor_callback); window = glfwOpenWindow(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 6d262ef..9320662 --- 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, width, height; - GLFWvidmode* modes = glfwGetVideoModes(&count); + GLFWvidmode* modes = glfwGetVideoModes(monitor, &count); glfwSetWindowSizeCallback(window_size_callback); glfwSetWindowCloseCallback(window_close_callback); @@ -129,7 +132,10 @@ glfwOpenWindowHint(GLFW_GREEN_BITS, mode->greenBits); glfwOpenWindowHint(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 = glfwOpenWindow(mode->width, mode->height, GLFW_FULLSCREEN, "Video Mode Test", @@ -191,6 +197,7 @@ int main(int argc, char** argv) { int ch, mode = LIST_MODE; + GLFWmonitor monitor = NULL; while ((ch = getopt(argc, argv, "th")) != -1) { @@ -216,10 +223,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); }