glfw/src/win32_monitor.c
Camilla Berglund d493a82f9e Various error fixes.
Fixed incorrect error types.  Added missing error string prefixes.
Removed some invalid or superfluous error emissions.  Clarified some
error strings.  Joined error string lines to aid grep.  Replaced some
generic error strings with specific ones.  Documentation work.

Fixes #450.
2015-03-15 15:52:27 +01:00

349 lines
10 KiB
C

//========================================================================
// GLFW 3.1 Win32 - 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>
#include <limits.h>
#include <malloc.h>
// These constants are missing on MinGW
#ifndef EDS_ROTATEDMODE
#define EDS_ROTATEDMODE 0x00000004
#endif
#ifndef DISPLAY_DEVICE_ACTIVE
#define DISPLAY_DEVICE_ACTIVE 0x00000001
#endif
//////////////////////////////////////////////////////////////////////////
////// GLFW internal API //////
//////////////////////////////////////////////////////////////////////////
// Change the current video mode
//
GLboolean _glfwSetVideoMode(_GLFWmonitor* monitor, const GLFWvidmode* desired)
{
GLFWvidmode current;
const GLFWvidmode* best;
DEVMODEW dm;
best = _glfwChooseVideoMode(monitor, desired);
_glfwPlatformGetVideoMode(monitor, &current);
if (_glfwCompareVideoModes(&current, best) == 0)
return GL_TRUE;
ZeroMemory(&dm, sizeof(dm));
dm.dmSize = sizeof(DEVMODEW);
dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL |
DM_DISPLAYFREQUENCY;
dm.dmPelsWidth = best->width;
dm.dmPelsHeight = best->height;
dm.dmBitsPerPel = best->redBits + best->greenBits + best->blueBits;
dm.dmDisplayFrequency = best->refreshRate;
if (dm.dmBitsPerPel < 15 || dm.dmBitsPerPel >= 24)
dm.dmBitsPerPel = 32;
if (ChangeDisplaySettingsExW(monitor->win32.adapterName,
&dm,
NULL,
CDS_FULLSCREEN,
NULL) != DISP_CHANGE_SUCCESSFUL)
{
_glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to set video mode");
return GL_FALSE;
}
monitor->win32.modeChanged = GL_TRUE;
return GL_TRUE;
}
// Restore the previously saved (original) video mode
//
void _glfwRestoreVideoMode(_GLFWmonitor* monitor)
{
if (monitor->win32.modeChanged)
{
ChangeDisplaySettingsExW(monitor->win32.adapterName,
NULL, NULL, CDS_FULLSCREEN, NULL);
monitor->win32.modeChanged = GL_FALSE;
}
}
//////////////////////////////////////////////////////////////////////////
////// GLFW platform API //////
//////////////////////////////////////////////////////////////////////////
_GLFWmonitor** _glfwPlatformGetMonitors(int* count)
{
int size = 0, found = 0;
_GLFWmonitor** monitors = NULL;
DWORD adapterIndex, displayIndex;
*count = 0;
for (adapterIndex = 0; ; adapterIndex++)
{
DISPLAY_DEVICEW adapter;
ZeroMemory(&adapter, sizeof(DISPLAY_DEVICEW));
adapter.cb = sizeof(DISPLAY_DEVICEW);
if (!EnumDisplayDevicesW(NULL, adapterIndex, &adapter, 0))
break;
if (!(adapter.StateFlags & DISPLAY_DEVICE_ACTIVE))
continue;
for (displayIndex = 0; ; displayIndex++)
{
DISPLAY_DEVICEW display;
char* name;
HDC dc;
ZeroMemory(&display, sizeof(DISPLAY_DEVICEW));
display.cb = sizeof(DISPLAY_DEVICEW);
if (!EnumDisplayDevicesW(adapter.DeviceName, displayIndex, &display, 0))
break;
if (found == size)
{
size += 4;
monitors = realloc(monitors, sizeof(_GLFWmonitor*) * size);
}
name = _glfwCreateUTF8FromWideString(display.DeviceString);
if (!name)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Win32: Failed to convert string to UTF-8");
continue;
}
dc = CreateDCW(L"DISPLAY", adapter.DeviceName, NULL, NULL);
monitors[found] = _glfwAllocMonitor(name,
GetDeviceCaps(dc, HORZSIZE),
GetDeviceCaps(dc, VERTSIZE));
DeleteDC(dc);
free(name);
wcscpy(monitors[found]->win32.adapterName, adapter.DeviceName);
wcscpy(monitors[found]->win32.displayName, display.DeviceName);
WideCharToMultiByte(CP_UTF8, 0,
adapter.DeviceName, -1,
monitors[found]->win32.publicAdapterName,
sizeof(monitors[found]->win32.publicAdapterName),
NULL, NULL);
WideCharToMultiByte(CP_UTF8, 0,
display.DeviceName, -1,
monitors[found]->win32.publicDisplayName,
sizeof(monitors[found]->win32.publicDisplayName),
NULL, NULL);
if (adapter.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE &&
displayIndex == 0)
{
_GLFW_SWAP_POINTERS(monitors[0], monitors[found]);
}
found++;
}
}
*count = found;
return monitors;
}
GLboolean _glfwPlatformIsSameMonitor(_GLFWmonitor* first, _GLFWmonitor* second)
{
return wcscmp(first->win32.displayName, second->win32.displayName) == 0;
}
void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos)
{
DEVMODEW settings;
ZeroMemory(&settings, sizeof(DEVMODEW));
settings.dmSize = sizeof(DEVMODEW);
EnumDisplaySettingsExW(monitor->win32.adapterName,
ENUM_CURRENT_SETTINGS,
&settings,
EDS_ROTATEDMODE);
if (xpos)
*xpos = settings.dmPosition.x;
if (ypos)
*ypos = settings.dmPosition.y;
}
GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found)
{
int modeIndex = 0, count = 0;
GLFWvidmode* result = NULL;
*found = 0;
for (;;)
{
int i;
GLFWvidmode mode;
DEVMODEW dm;
ZeroMemory(&dm, sizeof(DEVMODEW));
dm.dmSize = sizeof(DEVMODEW);
if (!EnumDisplaySettingsW(monitor->win32.adapterName, modeIndex, &dm))
break;
modeIndex++;
if (dm.dmBitsPerPel < 15)
{
// Skip modes with less than 15 BPP
continue;
}
mode.width = dm.dmPelsWidth;
mode.height = dm.dmPelsHeight;
mode.refreshRate = dm.dmDisplayFrequency;
_glfwSplitBPP(dm.dmBitsPerPel,
&mode.redBits,
&mode.greenBits,
&mode.blueBits);
for (i = 0; i < *found; i++)
{
if (_glfwCompareVideoModes(result + i, &mode) == 0)
break;
}
if (i < *found)
{
// This is a duplicate, so skip it
continue;
}
if (*found == count)
{
if (count)
count *= 2;
else
count = 128;
result = (GLFWvidmode*) realloc(result, count * sizeof(GLFWvidmode));
}
result[*found] = mode;
(*found)++;
}
return result;
}
void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode)
{
DEVMODEW dm;
ZeroMemory(&dm, sizeof(DEVMODEW));
dm.dmSize = sizeof(DEVMODEW);
EnumDisplaySettingsW(monitor->win32.adapterName, ENUM_CURRENT_SETTINGS, &dm);
mode->width = dm.dmPelsWidth;
mode->height = dm.dmPelsHeight;
mode->refreshRate = dm.dmDisplayFrequency;
_glfwSplitBPP(dm.dmBitsPerPel,
&mode->redBits,
&mode->greenBits,
&mode->blueBits);
}
void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
{
HDC dc;
WORD values[768];
dc = CreateDCW(L"DISPLAY", monitor->win32.adapterName, NULL, NULL);
GetDeviceGammaRamp(dc, values);
DeleteDC(dc);
_glfwAllocGammaArrays(ramp, 256);
memcpy(ramp->red, values + 0, 256 * sizeof(unsigned short));
memcpy(ramp->green, values + 256, 256 * sizeof(unsigned short));
memcpy(ramp->blue, values + 512, 256 * sizeof(unsigned short));
}
void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp)
{
HDC dc;
WORD values[768];
if (ramp->size != 256)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Win32: Gamma ramp size must be 256");
return;
}
memcpy(values + 0, ramp->red, 256 * sizeof(unsigned short));
memcpy(values + 256, ramp->green, 256 * sizeof(unsigned short));
memcpy(values + 512, ramp->blue, 256 * sizeof(unsigned short));
dc = CreateDCW(L"DISPLAY", monitor->win32.adapterName, NULL, NULL);
SetDeviceGammaRamp(dc, values);
DeleteDC(dc);
}
//////////////////////////////////////////////////////////////////////////
////// GLFW native API //////
//////////////////////////////////////////////////////////////////////////
GLFWAPI const char* glfwGetWin32Adapter(GLFWmonitor* handle)
{
_GLFWmonitor* monitor = (_GLFWmonitor*) handle;
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
return monitor->win32.publicAdapterName;
}
GLFWAPI const char* glfwGetWin32Monitor(GLFWmonitor* handle)
{
_GLFWmonitor* monitor = (_GLFWmonitor*) handle;
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
return monitor->win32.publicDisplayName;
}