diff --git a/.gitignore b/.gitignore index 678ddf95..53b8f785 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,7 @@ +*.a +CMakeCache.txt CMakeFiles cmake_install.cmake -CMakeCache.txt -Makefile cmake_uninstall.cmake .DS_Store src/config.h @@ -9,6 +9,9 @@ src/libglfw.pc src/libglfw.so src/libglfw.a src/libglfw.dylib +src/libglfw.lib +src/libglfwdll.lib +src/libglfw.dll examples/boing examples/gears examples/heightmap @@ -32,6 +35,7 @@ tests/peter tests/reopen tests/sharing tests/tearing +tests/version tests/windows tests/*.app tests/*.exe diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index d511b22d..852e482d 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,8 +1,14 @@ # This line is used to link with static libraries # Note that the library list should be updated to be obtained from -# the main CMakeLists.txt +# the main CMakeLists.txt link_libraries(libglfwStatic ${GLFW_LIBRARIES} ${OPENGL_glu_LIBRARY}) +if (UNIX AND NOT APPLE AND NOT CYGWIN) + find_library(MATH_LIBRARY m) + find_library(REALTIME_LIBRARY rt) + link_libraries(${MATH_LIBRARY} ${REALTIME_LIBRARY}) +endif (UNIX AND NOT APPLE AND NOT CYGWIN) + include_directories(${GLFW_SOURCE_DIR}/include ${GLFW_SOURCE_DIR}/support ${OPENGL_INCLUDE_DIR}) diff --git a/include/GL/glfw3.h b/include/GL/glfw3.h index e49654d1..93cc11a0 100644 --- a/include/GL/glfw3.h +++ b/include/GL/glfw3.h @@ -458,10 +458,22 @@ extern "C" { /* 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; + /* Window handle type */ typedef void* GLFWwindow; @@ -479,6 +491,7 @@ typedef void (* GLFWkeyfun)(GLFWwindow,int,int); typedef void (* GLFWcharfun)(GLFWwindow,int); typedef void* (* GLFWmallocfun)(size_t); typedef void (* GLFWfreefun)(void*); +typedef void (* GLFWmonitordevicefun)(GLFWmonitor,int); /* The video mode structure used by glfwGetVideoModes */ typedef struct @@ -528,8 +541,20 @@ GLFWAPI int glfwGetError(void); 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 int glfwGetVideoModes(GLFWvidmode* list, int maxcount); +GLFWAPI int glfwGetVideoModes(GLFWmonitor monitor, GLFWvidmode* list, int maxcount); GLFWAPI void glfwGetDesktopMode(GLFWvidmode* mode); /* Gamma ramp functions */ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f15089e9..ee510984 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,4 +1,8 @@ +if(WIN32) + add_definitions(-DWINVER=0x0501) +endif(WIN32) + if(UNIX) if(_GLFW_HAS_XRANDR) set(GLFW_PKGLIBS "${GLFW_PKGLIBS} xrandr") @@ -15,7 +19,7 @@ include_directories(${GLFW_SOURCE_DIR}/src ${GLFW_BINARY_DIR}/src ${GLFW_INCLUDE_DIR}) -set(common_SOURCES enable.c error.c fullscreen.c gamma.c init.c input.c +set(common_SOURCES monitor.c enable.c error.c fullscreen.c gamma.c init.c input.c joystick.c opengl.c time.c window.c) if(_GLFW_COCOA_NSGL) @@ -29,10 +33,10 @@ elseif(_GLFW_WIN32_WGL) set(libglfw_SOURCES ${common_SOURCES} win32_enable.c win32_fullscreen.c win32_gamma.c win32_init.c win32_joystick.c win32_opengl.c win32_time.c win32_window.c - win32_dllmain.c) + win32_dllmain.c win32_monitor.c) elseif(_GLFW_X11_GLX) - set(libglfw_SOURCES ${common_SOURCES} x11_enable.c x11_fullscreen.c - x11_gamma.c x11_init.c x11_joystick.c + set(libglfw_SOURCES ${common_SOURCES} x11_monitor.c x11_enable.c + x11_fullscreen.c x11_gamma.c x11_init.c x11_joystick.c x11_keysym2unicode.c x11_opengl.c x11_time.c x11_window.c) else() diff --git a/src/fullscreen.c b/src/fullscreen.c index 631f6193..011e1924 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 _glfwCompareVideoModes(const void* firstPtr, const void* secondPtr) { int firstBPP, secondBPP, firstSize, secondSize; GLFWvidmode* first = (GLFWvidmode*) firstPtr; @@ -100,9 +100,10 @@ void _glfwSplitBPP(int bpp, int* red, int* green, int* blue) // Get a list of available video modes //======================================================================== -GLFWAPI int glfwGetVideoModes(GLFWvidmode* list, int maxcount) +GLFWAPI int glfwGetVideoModes(GLFWmonitor handle, GLFWvidmode* list, int maxcount) { int count; + _GLFWmonitor* monitor = (_GLFWmonitor*) handle; if (!_glfwInitialized) { @@ -110,6 +111,13 @@ GLFWAPI int glfwGetVideoModes(GLFWvidmode* list, int maxcount) return 0; } + if (monitor == NULL) + { + _glfwSetError(GLFW_INVALID_VALUE, + "glfwGetVideoModes: Invalid monitor handle"); + return 0; + } + if (maxcount <= 0) { _glfwSetError(GLFW_INVALID_VALUE, @@ -125,9 +133,9 @@ GLFWAPI int glfwGetVideoModes(GLFWvidmode* list, int maxcount) return 0; } - count = _glfwPlatformGetVideoModes(list, maxcount); + count = _glfwPlatformGetVideoModes(monitor, list, maxcount); if (count > 0) - qsort(list, count, sizeof(GLFWvidmode), compareVideoModes); + qsort(list, count, sizeof(GLFWvidmode), _glfwCompareVideoModes); return count; } diff --git a/src/internal.h b/src/internal.h index 5992a0f4..91d507c1 100644 --- a/src/internal.h +++ b/src/internal.h @@ -80,6 +80,7 @@ typedef struct _GLFWwndconfig _GLFWwndconfig; typedef struct _GLFWfbconfig _GLFWfbconfig; typedef struct _GLFWwindow _GLFWwindow; typedef struct _GLFWlibrary _GLFWlibrary; +typedef struct _GLFWmonitor _GLFWmonitor; //------------------------------------------------------------------------ @@ -219,6 +220,27 @@ struct _GLFWwindow }; +//------------------------------------------------------------------------ +// 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; + + // These are defined in the current port's platform.h + _GLFW_PLATFORM_MONITOR_STATE; +}; + //------------------------------------------------------------------------ // Library global data //------------------------------------------------------------------------ @@ -229,6 +251,8 @@ struct _GLFWlibrary _GLFWwindow* windowListHead; _GLFWwindow* currentWindow; _GLFWwindow* activeWindow; + _GLFWwindow* cursorLockWindow; + _GLFWmonitor* monitorListHead; GLFWwindowsizefun windowSizeCallback; GLFWwindowclosefun windowCloseCallback; @@ -240,6 +264,7 @@ struct _GLFWlibrary GLFWscrollfun scrollCallback; GLFWkeyfun keyCallback; GLFWcharfun charCallback; + GLFWmonitordevicefun monitorCallback; GLFWthreadmodel threading; GLFWallocator allocator; @@ -281,7 +306,7 @@ void _glfwPlatformEnableSystemKeys(_GLFWwindow* window); void _glfwPlatformDisableSystemKeys(_GLFWwindow* window); // Fullscreen -int _glfwPlatformGetVideoModes(GLFWvidmode* list, int maxcount); +int _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, GLFWvidmode* list, int maxcount); void _glfwPlatformGetDesktopMode(GLFWvidmode* mode); // Gamma ramp @@ -332,6 +357,7 @@ void _glfwFree(void* ptr); // Fullscren management (fullscreen.c) void _glfwSplitBPP(int bpp, int* red, int* green, int* blue); +int _glfwCompareVideoModes(const void* firstPtr, const void* secondPtr); // Error handling (error.c) void _glfwSetError(int error, const char* description); diff --git a/src/monitor.c b/src/monitor.c new file mode 100644 index 00000000..3263eb9f --- /dev/null +++ b/src/monitor.c @@ -0,0 +1,147 @@ +//======================================================================== +// 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 +// +// 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" + + +////////////////////////////////////////////////////////////////////////// +////// 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; +} + diff --git a/src/win32_fullscreen.c b/src/win32_fullscreen.c index de3d898b..08f5e93e 100644 --- a/src/win32_fullscreen.c +++ b/src/win32_fullscreen.c @@ -182,71 +182,58 @@ void _glfwRestoreVideoMode(void) // Get a list of available video modes //======================================================================== -int _glfwPlatformGetVideoModes(GLFWvidmode* list, int maxcount) +int _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, GLFWvidmode* list, int maxcount) { - int count, success, mode, i, j; - int m1, m2, bpp, r, g, b; - DEVMODE dm; + DEVMODE deviceMode; + DWORD deviceModeNum; - // Loop through all video modes and extract all the UNIQUE modes - count = 0; - mode = 0; + GLFWvidmode* vidModes; + int vidModesCount; + GLFWvidmode vidMode; - do + deviceMode.dmSize = sizeof(DEVMODE); + deviceModeNum = 0; + + vidModes = NULL; + vidModesCount = 0; + + for (;;) { - // Get video mode properties - dm.dmSize = sizeof(DEVMODE); - success = EnumDisplaySettings(NULL, mode, &dm); + if (!EnumDisplaySettings(monitor->Win32.name, deviceModeNum, &deviceMode)) + break; - // Is it a valid mode? (only list depths >= 15 bpp) - if (success && dm.dmBitsPerPel >= 15) - { - // Convert to RGB, and back to bpp ("mask out" alpha bits etc) - _glfwSplitBPP(dm.dmBitsPerPel, &r, &g, &b); - bpp = r + g + b; + if (vidModesCount >= maxcount) + break; - // Mode "code" for this mode - m1 = (bpp << 25) | (dm.dmPelsWidth * dm.dmPelsHeight); + deviceModeNum++; - // Insert mode in list (sorted), and avoid duplicates - for (i = 0; i < count; i++) - { - // Mode "code" for already listed mode - bpp = list[i].redBits + list[i].greenBits + list[i].blueBits; - m2 = (bpp << 25) | (list[i].width * list[i].height); - if (m1 <= m2) - break; - } + if (deviceMode.dmBitsPerPel < 15) + continue; - // New entry at the end of the list? - if (i >= count) - { - list[count].width = dm.dmPelsWidth; - list[count].height = dm.dmPelsHeight; - list[count].redBits = r; - list[count].greenBits = g; - list[count].blueBits = b; - count ++; - } - // Insert new entry in the list? - else if (m1 < m2) - { - for (j = count; j > i; j--) - list[j] = list[j - 1]; + vidMode.height = deviceMode.dmPelsHeight; + vidMode.width = deviceMode.dmPelsWidth; + // Convert to RGB, and back to bpp ("mask out" alpha bits etc) + _glfwSplitBPP(deviceMode.dmBitsPerPel, + &vidMode.redBits, + &vidMode.greenBits, + &vidMode.blueBits); - list[i].width = dm.dmPelsWidth; - list[i].height = dm.dmPelsHeight; - list[i].redBits = r; - list[i].greenBits = g; - list[i].blueBits = b; - count++; - } - } - mode++; + // skip duplicates. + if (vidModes && bsearch(&vidMode, vidModes, vidModesCount, sizeof(GLFWvidmode), _glfwCompareVideoModes)) + continue; + + vidModes = realloc(vidModes, sizeof(GLFWvidmode) * ++vidModesCount); + memcpy(vidModes + (vidModesCount - 1), &vidMode, sizeof(GLFWvidmode)); + + qsort(vidModes, vidModesCount, sizeof(GLFWvidmode), _glfwCompareVideoModes); } - while (success && (count < maxcount)); - return count; + if (list && maxcount) + memcpy(list, vidModes, sizeof(GLFWvidmode) * min(vidModesCount, maxcount)); + + free(vidModes); + + return vidModesCount; } diff --git a/src/win32_init.c b/src/win32_init.c index 0756b0f2..0f1c27c0 100644 --- a/src/win32_init.c +++ b/src/win32_init.c @@ -165,6 +165,8 @@ int _glfwPlatformInit(void) _glfwPlatformGetGammaRamp(&_glfwLibrary.originalRamp); _glfwLibrary.currentRamp = _glfwLibrary.originalRamp; + _glfwInitMonitors(); + _glfwInitTimer(); return GL_TRUE; @@ -180,6 +182,8 @@ int _glfwPlatformTerminate(void) // Restore the original gamma ramp _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 00000000..7b03b9fb --- /dev/null +++ b/src/win32_monitor.c @@ -0,0 +1,231 @@ +//======================================================================== +// 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 +// +// 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 +#include + +// The MinGW package for Debian lacks this +#ifndef EDS_ROTATEDMODE +#define EDS_ROTATEDMODE 0x00000004 +#endif + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +_GLFWmonitor** _glfwCreateMonitor(_GLFWmonitor** current, + DISPLAY_DEVICE* adapter, + DISPLAY_DEVICE* monitor, + DEVMODE* setting) +{ + HDC dc = NULL; + + *current = _glfwMalloc(sizeof(_GLFWmonitor)); + memset(*current, 0, sizeof(_GLFWmonitor)); + + dc = CreateDC("DISPLAY", monitor->DeviceString, NULL, NULL); + + (*current)->physicalWidth = GetDeviceCaps(dc, HORZSIZE); + (*current)->physicalHeight = GetDeviceCaps(dc, VERTSIZE); + + DeleteDC(dc); + + (*current)->name = _glfwMalloc(strlen(monitor->DeviceName) + 1); + memcpy((*current)->name, monitor->DeviceName, strlen(monitor->DeviceName) + 1); + (*current)->name[strlen(monitor->DeviceName)] = '\0'; + + (*current)->screenX = setting->dmPosition.x; + (*current)->screenY = setting->dmPosition.y; + + memcpy((*current)->Win32.name, adapter->DeviceName, 32); + return &((*current)->next); +} + +_GLFWmonitor* _glfwDestroyMonitor(_GLFWmonitor* monitor) +{ + _GLFWmonitor* result; + + result = monitor->next; + + _glfwFree(monitor->name); + _glfwFree(monitor); + + return result; +} + +// todo: This is ugly. The platform should only allocate a list of the current devices. +// The platform independent code should be in charge of the handling for the initial +// setup, refreshing and freeing the list. +void _glfwInitMonitors(void) +{ + _GLFWmonitor** curMonitor; + + DISPLAY_DEVICE adapter; + DWORD adapterNum; + + DISPLAY_DEVICE monitor; + + DEVMODE setting; + DWORD settingNum; + + curMonitor = &_glfwLibrary.monitorListHead; + + adapter.cb = sizeof(DISPLAY_DEVICE); + adapterNum = 0; + + monitor.cb = sizeof(DISPLAY_DEVICE); + setting.dmSize = sizeof(DEVMODE); + settingNum = 0; + + 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); + } +} + +void _glfwRefreshMonitors(void) +{ + DISPLAY_DEVICE adapter; + DWORD adapterNum = 0; + + DISPLAY_DEVICE monitor; + + DEVMODE setting; + + _GLFWmonitor* newMonitorList = NULL; + _GLFWmonitor** curMonitor = &newMonitorList; + + _GLFWmonitor* curNewMonitor; + _GLFWmonitor* curOldMonitor; + + 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); + } + + 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; +} + +void _glfwTerminateMonitors(void) +{ + while (_glfwLibrary.monitorListHead) + _glfwLibrary.monitorListHead = _glfwDestroyMonitor(_glfwLibrary.monitorListHead); +} + diff --git a/src/win32_platform.h b/src/win32_platform.h index 074e28ba..3c2892c7 100644 --- a/src/win32_platform.h +++ b/src/win32_platform.h @@ -47,6 +47,7 @@ #include #include +#include // 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 @@ -210,6 +211,7 @@ typedef DWORD (WINAPI * TIMEGETTIME_T) (void); #define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowWin32 Win32 #define _GLFW_PLATFORM_LIBRARY_STATE _GLFWlibraryWin32 Win32 #define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextWGL WGL +#define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorWin32 Win32 //======================================================================== @@ -318,6 +320,14 @@ typedef struct _GLFWlibraryWin32 } _GLFWlibraryWin32; +//------------------------------------------------------------------------ +// Platform-specific monitor structure +//------------------------------------------------------------------------ +typedef struct _GLFWmonitorWin32 +{ + char name[32]; + +} _GLFWmonitorWin32; //======================================================================== // Prototypes for platform specific internal functions @@ -326,6 +336,11 @@ typedef struct _GLFWlibraryWin32 // Time void _glfwInitTimer(void); +// Monitor support +void _glfwInitMonitors(void); +void _glfwRefreshMonitors(void); +void _glfwTerminateMonitors(void); + // Fullscreen support void _glfwSetVideoMode(int* width, int* height, int* bpp, int* refreshRate, diff --git a/src/win32_window.c b/src/win32_window.c index e2619acf..41199e5f 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -30,7 +30,6 @@ #include "internal.h" -#include #include @@ -1079,6 +1078,16 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, break; } + + case WM_DEVICECHANGE: + { + if (DBT_DEVNODES_CHANGED == wParam) + { + _glfwRefreshMonitors(); + return TRUE; + } + break; + } } // Pass all unhandled messages to DefWindowProc @@ -1780,7 +1789,7 @@ void _glfwPlatformPollEvents(void) window = _glfwLibrary.activeWindow; if (window) { - window->Win32.cursorCentered = GL_FALSE; + window->Win32.cursorCentered = GL_TRUE; window->Win32.oldMouseX = window->width / 2; window->Win32.oldMouseY = window->height / 2; } @@ -1902,3 +1911,4 @@ void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode) } } + diff --git a/src/x11_fullscreen.c b/src/x11_fullscreen.c index bb0a3d53..f0a3f194 100644 --- a/src/x11_fullscreen.c +++ b/src/x11_fullscreen.c @@ -316,11 +316,26 @@ struct _glfwResolution int height; }; +int _glfwCompareResolution(const void* left, const void* right) +{ + int result = 0; + const struct _glfwResolution* leftResolution = left; + const struct _glfwResolution* rightResolution = right; + + result = leftResolution->height - rightResolution->height; + if (result == 0) + { + result = leftResolution->width - rightResolution->width; + } + + return result; +} + //======================================================================== // List available video modes //======================================================================== -int _glfwPlatformGetVideoModes(GLFWvidmode* list, int maxcount) +int _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, GLFWvidmode* list, int maxcount) { int count, k, l, r, g, b, rgba, gl; int depth, screen; @@ -380,23 +395,37 @@ int _glfwPlatformGetVideoModes(GLFWvidmode* list, int maxcount) if (_glfwLibrary.X11.RandR.available) { #if defined(_GLFW_HAS_XRANDR) - XRRScreenConfiguration* sc; - XRRScreenSize* sizelist; - int sizecount; + XRRScreenResources* resource; + unsigned int a; + resource = XRRGetScreenResources(_glfwLibrary.X11.display, _glfwLibrary.X11.root); - sc = XRRGetScreenInfo(_glfwLibrary.X11.display, _glfwLibrary.X11.root); - sizelist = XRRConfigSizes(sc, &sizecount); + resarray = (struct _glfwResolution*) _glfwMalloc(sizeof(struct _glfwResolution) * monitor->X11.output->nmode); - resarray = (struct _glfwResolution*) _glfwMalloc(sizeof(struct _glfwResolution) * sizecount); - - for (k = 0; k < sizecount; k++) + for (k = 0; k < monitor->X11.output->nmode; k++) { - resarray[rescount].width = sizelist[k].width; - resarray[rescount].height = sizelist[k].height; - rescount++; + for (a = 0; a < resource->nmode; a++) + { + if (resource->modes[a].id != monitor->X11.output->modes[k]) + { + continue; + } + + struct _glfwResolution res = { + resource->modes[a].width, + resource->modes[a].height + }; + + if (!bsearch(&res, resarray, rescount, sizeof(struct _glfwResolution), _glfwCompareResolution)) + { + resarray[rescount].width = resource->modes[a].width; + resarray[rescount].height = resource->modes[a].height; + rescount++; + qsort(resarray, rescount, sizeof(struct _glfwResolution), _glfwCompareResolution); + } + } } - XRRFreeScreenConfigInfo(sc); + XRRFreeScreenResources(resource); #endif /*_GLFW_HAS_XRANDR*/ } else if (_glfwLibrary.X11.VidMode.available) diff --git a/src/x11_init.c b/src/x11_init.c index 4d3c0f74..5697eb37 100644 --- a/src/x11_init.c +++ b/src/x11_init.c @@ -578,6 +578,8 @@ int _glfwPlatformInit(void) _glfwInitJoysticks(); + _glfwInitMonitors(); + // Start the timer _glfwInitTimer(); @@ -599,6 +601,8 @@ int _glfwPlatformTerminate(void) terminateDisplay(); + _glfwTerminateMonitors(); + _glfwTerminateJoysticks(); // Unload libGL.so if necessary diff --git a/src/x11_monitor.c b/src/x11_monitor.c new file mode 100644 index 00000000..e827fb35 --- /dev/null +++ b/src/x11_monitor.c @@ -0,0 +1,136 @@ +//======================================================================== +// 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 +// +// 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 +#include + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +#if defined (_GLFW_HAS_XRANDR) +_GLFWmonitor** _glfwCreateMonitor(_GLFWmonitor** current, + XRROutputInfo* outputInfo, + XRRCrtcInfo* crtcInfo) +{ + *current = _glfwMalloc(sizeof(_GLFWmonitor)); + memset(*current, 0, sizeof(_GLFWmonitor)); + + (*current)->physicalWidth = outputInfo->mm_width; + (*current)->physicalHeight = outputInfo->mm_height; + + (*current)->name = _glfwMalloc(strlen(outputInfo->name) + 1); + memcpy((*current)->name, outputInfo->name, strlen(outputInfo->name) + 1); + (*current)->name[strlen(outputInfo->name)] = '\0'; + + (*current)->screenX = crtcInfo->x; + (*current)->screenY = crtcInfo->y; + + (*current)->X11.output = outputInfo; + return &((*current)->next); +} +#endif /*_GLFW_HAS_XRANDR*/ + +_GLFWmonitor* _glfwDestroyMonitor(_GLFWmonitor* monitor) +{ + _GLFWmonitor* result; + + result = monitor->next; + +#if defined (_GLFW_HAS_XRANDR) + XRRFreeOutputInfo(monitor->X11.output); +#endif /*_GLFW_HAS_XRANDR*/ + + _glfwFree(monitor->name); + _glfwFree(monitor); + + return result; +} + +void _glfwInitMonitors(void) +{ + _glfwLibrary.monitorListHead = NULL; + + if (_glfwLibrary.X11.RandR.available) + { +#if defined (_GLFW_HAS_XRANDR) + XRRScreenResources* resources; + int outputIDX; + _GLFWmonitor** curMonitor; + + curMonitor = &_glfwLibrary.monitorListHead; + + resources = XRRGetScreenResources(_glfwLibrary.X11.display, + _glfwLibrary.X11.root); + + for (outputIDX = 0; outputIDX < resources->noutput; outputIDX++) + { + // physical device + XRROutputInfo* outputInfo = NULL; + // logical surface + XRRCrtcInfo* crtcInfo = NULL; + int crtcIDX; + + outputInfo = XRRGetOutputInfo(_glfwLibrary.X11.display, + resources, + resources->outputs[outputIDX]); + + if (outputInfo->connection == RR_Connected) + { + for (crtcIDX = 0; crtcIDX < outputInfo->ncrtc; crtcIDX++) + { + if (outputInfo->crtc == outputInfo->crtcs[crtcIDX]) + { + crtcInfo = XRRGetCrtcInfo(_glfwLibrary.X11.display, + resources, + outputInfo->crtcs[crtcIDX]); + break; + } + } + + curMonitor = _glfwCreateMonitor(curMonitor, outputInfo, crtcInfo); + + // Freeing of the outputInfo is done in _glfwDestroyMonitor + XRRFreeCrtcInfo(crtcInfo); + } + } +#endif /*_GLFW_HAS_XRANDR*/ + } +} + +void _glfwTerminateMonitors(void) +{ + while (_glfwLibrary.monitorListHead) + _glfwLibrary.monitorListHead = _glfwDestroyMonitor(_glfwLibrary.monitorListHead); +} + diff --git a/src/x11_platform.h b/src/x11_platform.h index 46f09f1a..41e8167e 100644 --- a/src/x11_platform.h +++ b/src/x11_platform.h @@ -91,6 +91,7 @@ #define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowX11 X11 #define _GLFW_PLATFORM_LIBRARY_STATE _GLFWlibraryX11 X11 #define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextGLX GLX +#define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorX11 X11 //======================================================================== @@ -247,6 +248,20 @@ GLFWGLOBAL struct { } _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 //======================================================================== @@ -264,6 +279,10 @@ void _glfwRestoreVideoMode(int screen); void _glfwInitJoysticks(void); void _glfwTerminateJoysticks(void); +// Monitors +void _glfwInitMonitors(void); +void _glfwTerminateMonitors(void); + // Unicode support long _glfwKeySym2Unicode(KeySym keysym); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 5adbf351..5199592c 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -2,6 +2,12 @@ set(STATIC_DEPS libglfwStatic ${GLFW_LIBRARIES} ${OPENGL_glu_LIBRARY}) set(SHARED_DEPS libglfwShared ${GLFW_LIBRARIES} ${OPENGL_glu_LIBRARY}) +if (UNIX AND NOT APPLE AND NOT CYGWIN) + find_library(MATH_LIBRARY m) + find_library(REALTIME_LIBRARY rt) + link_libraries(${MATH_LIBRARY} ${REALTIME_LIBRARY}) +endif (UNIX AND NOT APPLE AND NOT CYGWIN) + include_directories(${GLFW_SOURCE_DIR}/include ${GLFW_SOURCE_DIR}/support ${OPENGL_INCLUDE_DIR}) diff --git a/tests/events.c b/tests/events.c index ac758100..1a1280a3 100644 --- a/tests/events.c +++ b/tests/events.c @@ -216,6 +216,19 @@ static const char* get_character_string(int character) 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", @@ -330,6 +343,16 @@ static void char_callback(GLFWwindow window, int character) get_character_string(character)); } +void monitor_callback(GLFWmonitor monitor, int event) +{ + printf("%08x at %0.3f: Monitor %s %s", + counter++, + glfwGetTime(), + glfwGetMonitorString(monitor, GLFW_MONITOR_NAME), + get_monitor_event_name(event)); + +} + int main(void) { GLFWwindow window; @@ -354,6 +377,7 @@ int main(void) 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/listmodes.c b/tests/listmodes.c index a4648ef6..2ba61577 100644 --- a/tests/listmodes.c +++ b/tests/listmodes.c @@ -18,6 +18,7 @@ static void print_mode(GLFWvidmode* mode) int main(void) { + GLFWmonitor monitor; GLFWvidmode dtmode, modes[400]; int modecount, i; @@ -32,16 +33,30 @@ int main(void) printf("Desktop mode: "); print_mode(&dtmode); - // List available video modes - modecount = glfwGetVideoModes(modes, sizeof(modes) / sizeof(GLFWvidmode)); - printf("Available modes:\n"); - for (i = 0; i < modecount; i++) + monitor = NULL; + + while ((monitor = glfwGetNextMonitor(monitor))) { - printf("%3i: ", i); - print_mode(modes + i); + printf("Monitor name: %s\n" + "Physical dimensions: %dmm x %dmm\n" + "Logical position: (%d,%d)\n", + glfwGetMonitorString(monitor, GLFW_MONITOR_NAME), + glfwGetMonitorParam(monitor, GLFW_MONITOR_PHYSICAL_WIDTH), + glfwGetMonitorParam(monitor, GLFW_MONITOR_PHYSICAL_HEIGHT), + glfwGetMonitorParam(monitor, GLFW_MONITOR_SCREEN_POS_X), + glfwGetMonitorParam(monitor, GLFW_MONITOR_SCREEN_POS_Y)); + + // List available video modes + modecount = glfwGetVideoModes(monitor, modes, sizeof(modes) / sizeof(GLFWvidmode)); + printf("Available modes:\n"); + + for (i = 0; i < modecount; i++) + { + printf("%3i: ", i); + print_mode(modes + i); + } } - glfwTerminate(); exit(EXIT_SUCCESS); }