mirror of
				https://github.com/glfw/glfw.git
				synced 2025-10-31 04:32:26 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			942 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			942 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| //========================================================================
 | |
| // GLFW 3.4 Win32 - www.glfw.org
 | |
| //------------------------------------------------------------------------
 | |
| // Copyright (c) 2002-2006 Marcus Geelnard
 | |
| // Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.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.
 | |
| //
 | |
| //========================================================================
 | |
| // Please use C89 style variable declarations in this file because VS 2010
 | |
| //========================================================================
 | |
| 
 | |
| #include "internal.h"
 | |
| 
 | |
| #if defined(_GLFW_WIN32)
 | |
| 
 | |
| #include <stdlib.h>
 | |
| #include <string.h>
 | |
| #include <limits.h>
 | |
| #include <wchar.h>
 | |
| 
 | |
| 
 | |
| #if WINVER < 0x0601 // To be able to compile on windows Vista and XP even though the feature won't be used.
 | |
| 
 | |
| typedef struct DISPLAYCONFIG_PATH_SOURCE_INFO
 | |
| {
 | |
|     LUID   adapterId;
 | |
|     UINT32 id;
 | |
|     union
 | |
|     {
 | |
|         UINT32 modeInfoIdx;
 | |
|         struct
 | |
|         {
 | |
|             UINT32 cloneGroupId : 16;
 | |
|             UINT32 sourceModeInfoIdx : 16;
 | |
|         } DUMMYSTRUCTNAME;
 | |
|     } DUMMYUNIONNAME;
 | |
|     UINT32 statusFlags;
 | |
| } DISPLAYCONFIG_PATH_SOURCE_INFO;
 | |
| 
 | |
| typedef enum
 | |
| {
 | |
|     DISPLAYCONFIG_OUTPUT_TECHNOLOGY_OTHER = -1,
 | |
|     DISPLAYCONFIG_OUTPUT_TECHNOLOGY_HD15 = 0,
 | |
|     DISPLAYCONFIG_OUTPUT_TECHNOLOGY_SVIDEO = 1,
 | |
|     DISPLAYCONFIG_OUTPUT_TECHNOLOGY_COMPOSITE_VIDEO = 2,
 | |
|     DISPLAYCONFIG_OUTPUT_TECHNOLOGY_COMPONENT_VIDEO = 3,
 | |
|     DISPLAYCONFIG_OUTPUT_TECHNOLOGY_DVI = 4,
 | |
|     DISPLAYCONFIG_OUTPUT_TECHNOLOGY_HDMI = 5,
 | |
|     DISPLAYCONFIG_OUTPUT_TECHNOLOGY_LVDS = 6,
 | |
|     DISPLAYCONFIG_OUTPUT_TECHNOLOGY_D_JPN = 8,
 | |
|     DISPLAYCONFIG_OUTPUT_TECHNOLOGY_SDI = 9,
 | |
|     DISPLAYCONFIG_OUTPUT_TECHNOLOGY_DISPLAYPORT_EXTERNAL = 10,
 | |
|     DISPLAYCONFIG_OUTPUT_TECHNOLOGY_DISPLAYPORT_EMBEDDED = 11,
 | |
|     DISPLAYCONFIG_OUTPUT_TECHNOLOGY_UDI_EXTERNAL = 12,
 | |
|     DISPLAYCONFIG_OUTPUT_TECHNOLOGY_UDI_EMBEDDED = 13,
 | |
|     DISPLAYCONFIG_OUTPUT_TECHNOLOGY_SDTVDONGLE = 14,
 | |
|     DISPLAYCONFIG_OUTPUT_TECHNOLOGY_MIRACAST = 15,
 | |
|     DISPLAYCONFIG_OUTPUT_TECHNOLOGY_INDIRECT_WIRED = 16,
 | |
|     DISPLAYCONFIG_OUTPUT_TECHNOLOGY_INDIRECT_VIRTUAL = 17,
 | |
|     DISPLAYCONFIG_OUTPUT_TECHNOLOGY_DISPLAYPORT_USB_TUNNEL,
 | |
|     DISPLAYCONFIG_OUTPUT_TECHNOLOGY_INTERNAL = (int)0x80000000,     // Cast required to enforce 4 byte enum.
 | |
|     DISPLAYCONFIG_OUTPUT_TECHNOLOGY_FORCE_UINT32 = (int)0xFFFFFFFF  // Cast required to enforce 4 byte enum.
 | |
| } DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY;
 | |
| 
 | |
| typedef enum
 | |
| {
 | |
|     DISPLAYCONFIG_ROTATION_IDENTITY = 1,
 | |
|     DISPLAYCONFIG_ROTATION_ROTATE90 = 2,
 | |
|     DISPLAYCONFIG_ROTATION_ROTATE180 = 3,
 | |
|     DISPLAYCONFIG_ROTATION_ROTATE270 = 4,
 | |
|     DISPLAYCONFIG_ROTATION_FORCE_UINT32 = 0xFFFFFFFF
 | |
| } DISPLAYCONFIG_ROTATION;
 | |
| 
 | |
| typedef enum
 | |
| {
 | |
|     DISPLAYCONFIG_SCALING_IDENTITY = 1,
 | |
|     DISPLAYCONFIG_SCALING_CENTERED = 2,
 | |
|     DISPLAYCONFIG_SCALING_STRETCHED = 3,
 | |
|     DISPLAYCONFIG_SCALING_ASPECTRATIOCENTEREDMAX = 4,
 | |
|     DISPLAYCONFIG_SCALING_CUSTOM = 5,
 | |
|     DISPLAYCONFIG_SCALING_PREFERRED = 128,
 | |
|     DISPLAYCONFIG_SCALING_FORCE_UINT32 = 0xFFFFFFFF
 | |
| } DISPLAYCONFIG_SCALING;
 | |
| 
 | |
| typedef struct DISPLAYCONFIG_RATIONAL
 | |
| {
 | |
|     UINT32 Numerator;
 | |
|     UINT32 Denominator;
 | |
| } DISPLAYCONFIG_RATIONAL;
 | |
| 
 | |
| typedef enum
 | |
| {
 | |
|     DISPLAYCONFIG_SCANLINE_ORDERING_UNSPECIFIED = 0,
 | |
|     DISPLAYCONFIG_SCANLINE_ORDERING_PROGRESSIVE = 1,
 | |
|     DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED = 2,
 | |
|     DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED_UPPERFIELDFIRST,
 | |
|     DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED_LOWERFIELDFIRST = 3,
 | |
|     DISPLAYCONFIG_SCANLINE_ORDERING_FORCE_UINT32 = 0xFFFFFFFF
 | |
| } DISPLAYCONFIG_SCANLINE_ORDERING;
 | |
| 
 | |
| typedef struct DISPLAYCONFIG_PATH_TARGET_INFO
 | |
| {
 | |
|     LUID                                  adapterId;
 | |
|     UINT32                                id;
 | |
|     union
 | |
|     {
 | |
|         UINT32 modeInfoIdx;
 | |
|         struct
 | |
|         {
 | |
|             UINT32 desktopModeInfoIdx : 16;
 | |
|             UINT32 targetModeInfoIdx : 16;
 | |
|         } DUMMYSTRUCTNAME;
 | |
|     } DUMMYUNIONNAME;
 | |
|     DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY outputTechnology;
 | |
|     DISPLAYCONFIG_ROTATION                rotation;
 | |
|     DISPLAYCONFIG_SCALING                 scaling;
 | |
|     DISPLAYCONFIG_RATIONAL                refreshRate;
 | |
|     DISPLAYCONFIG_SCANLINE_ORDERING       scanLineOrdering;
 | |
|     BOOL                                  targetAvailable;
 | |
|     UINT32                                statusFlags;
 | |
| } DISPLAYCONFIG_PATH_TARGET_INFO;
 | |
| 
 | |
| typedef struct DISPLAYCONFIG_PATH_INFO
 | |
| {
 | |
|     DISPLAYCONFIG_PATH_SOURCE_INFO sourceInfo;
 | |
|     DISPLAYCONFIG_PATH_TARGET_INFO targetInfo;
 | |
|     UINT32                         flags;
 | |
| } DISPLAYCONFIG_PATH_INFO;
 | |
| 
 | |
| typedef enum
 | |
| {
 | |
|     DISPLAYCONFIG_MODE_INFO_TYPE_SOURCE = 1,
 | |
|     DISPLAYCONFIG_MODE_INFO_TYPE_TARGET = 2,
 | |
|     DISPLAYCONFIG_MODE_INFO_TYPE_DESKTOP_IMAGE = 3,
 | |
|     DISPLAYCONFIG_MODE_INFO_TYPE_FORCE_UINT32 = 0xFFFFFFFF
 | |
| } DISPLAYCONFIG_MODE_INFO_TYPE;
 | |
| 
 | |
| typedef struct DISPLAYCONFIG_2DREGION
 | |
| {
 | |
|     UINT32 cx;
 | |
|     UINT32 cy;
 | |
| } DISPLAYCONFIG_2DREGION;
 | |
| 
 | |
| typedef struct DISPLAYCONFIG_VIDEO_SIGNAL_INFO
 | |
| {
 | |
|     UINT64                          pixelRate;
 | |
|     DISPLAYCONFIG_RATIONAL          hSyncFreq;
 | |
|     DISPLAYCONFIG_RATIONAL          vSyncFreq;
 | |
|     DISPLAYCONFIG_2DREGION          activeSize;
 | |
|     DISPLAYCONFIG_2DREGION          totalSize;
 | |
|     union
 | |
|     {
 | |
|         struct
 | |
|         {
 | |
|             UINT32 videoStandard : 16;
 | |
|             UINT32 vSyncFreqDivider : 6;
 | |
|             UINT32 reserved : 10;
 | |
|         } AdditionalSignalInfo;
 | |
|         UINT32 videoStandard;
 | |
|     } DUMMYUNIONNAME;
 | |
|     DISPLAYCONFIG_SCANLINE_ORDERING scanLineOrdering;
 | |
| } DISPLAYCONFIG_VIDEO_SIGNAL_INFO;
 | |
| 
 | |
| typedef struct DISPLAYCONFIG_TARGET_MODE
 | |
| {
 | |
|   DISPLAYCONFIG_VIDEO_SIGNAL_INFO targetVideoSignalInfo;
 | |
| } DISPLAYCONFIG_TARGET_MODE;
 | |
| 
 | |
| typedef enum
 | |
| {
 | |
|     DISPLAYCONFIG_PIXELFORMAT_8BPP = 1,
 | |
|     DISPLAYCONFIG_PIXELFORMAT_16BPP = 2,
 | |
|     DISPLAYCONFIG_PIXELFORMAT_24BPP = 3,
 | |
|     DISPLAYCONFIG_PIXELFORMAT_32BPP = 4,
 | |
|     DISPLAYCONFIG_PIXELFORMAT_NONGDI = 5,
 | |
|     DISPLAYCONFIG_PIXELFORMAT_FORCE_UINT32 = 0xffffffff
 | |
| } DISPLAYCONFIG_PIXELFORMAT;
 | |
| 
 | |
| typedef struct DISPLAYCONFIG_SOURCE_MODE
 | |
| {
 | |
|     UINT32                    width;
 | |
|     UINT32                    height;
 | |
|     DISPLAYCONFIG_PIXELFORMAT pixelFormat;
 | |
|     POINTL                    position;
 | |
| } DISPLAYCONFIG_SOURCE_MODE;
 | |
| 
 | |
| typedef struct DISPLAYCONFIG_DESKTOP_IMAGE_INFO
 | |
| {
 | |
|     POINTL PathSourceSize;
 | |
|     RECTL  DesktopImageRegion;
 | |
|     RECTL  DesktopImageClip;
 | |
| } DISPLAYCONFIG_DESKTOP_IMAGE_INFO;
 | |
| 
 | |
| typedef struct DISPLAYCONFIG_MODE_INFO
 | |
| {
 | |
|     DISPLAYCONFIG_MODE_INFO_TYPE infoType;
 | |
|     UINT32                       id;
 | |
|     LUID                         adapterId;
 | |
|     union
 | |
|     {
 | |
|       DISPLAYCONFIG_TARGET_MODE        targetMode;
 | |
|       DISPLAYCONFIG_SOURCE_MODE        sourceMode;
 | |
|       DISPLAYCONFIG_DESKTOP_IMAGE_INFO desktopImageInfo;
 | |
|     } DUMMYUNIONNAME;
 | |
| } DISPLAYCONFIG_MODE_INFO;
 | |
| 
 | |
| const UINT32 QDC_ONLY_ACTIVE_PATHS = 0x00000002;
 | |
| 
 | |
| typedef enum
 | |
| {
 | |
|     DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME = 1,
 | |
|     DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME = 2,
 | |
|     DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_PREFERRED_MODE = 3,
 | |
|     DISPLAYCONFIG_DEVICE_INFO_GET_ADAPTER_NAME = 4,
 | |
|     DISPLAYCONFIG_DEVICE_INFO_SET_TARGET_PERSISTENCE = 5,
 | |
|     DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_BASE_TYPE = 6,
 | |
|     DISPLAYCONFIG_DEVICE_INFO_GET_SUPPORT_VIRTUAL_RESOLUTION = 7,
 | |
|     DISPLAYCONFIG_DEVICE_INFO_SET_SUPPORT_VIRTUAL_RESOLUTION = 8,
 | |
|     DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO = 9,
 | |
|     DISPLAYCONFIG_DEVICE_INFO_SET_ADVANCED_COLOR_STATE = 10,
 | |
|     DISPLAYCONFIG_DEVICE_INFO_GET_SDR_WHITE_LEVEL = 11,
 | |
|     DISPLAYCONFIG_DEVICE_INFO_GET_MONITOR_SPECIALIZATION,
 | |
|     DISPLAYCONFIG_DEVICE_INFO_SET_MONITOR_SPECIALIZATION,
 | |
|     DISPLAYCONFIG_DEVICE_INFO_FORCE_UINT32 = 0xFFFFFFFF
 | |
| } DISPLAYCONFIG_DEVICE_INFO_TYPE;
 | |
| 
 | |
| typedef struct DISPLAYCONFIG_DEVICE_INFO_HEADER {
 | |
|   DISPLAYCONFIG_DEVICE_INFO_TYPE type;
 | |
|   UINT32                         size;
 | |
|   LUID                           adapterId;
 | |
|   UINT32                         id;
 | |
| } DISPLAYCONFIG_DEVICE_INFO_HEADER;
 | |
| 
 | |
| typedef struct DISPLAYCONFIG_SOURCE_DEVICE_NAME
 | |
| {
 | |
|     DISPLAYCONFIG_DEVICE_INFO_HEADER header;
 | |
|     WCHAR                            viewGdiDeviceName[CCHDEVICENAME];
 | |
| } DISPLAYCONFIG_SOURCE_DEVICE_NAME;
 | |
| 
 | |
| typedef struct DISPLAYCONFIG_TARGET_DEVICE_NAME_FLAGS
 | |
| {
 | |
|     union
 | |
|     {
 | |
|         struct
 | |
|         {
 | |
|             UINT32 friendlyNameFromEdid : 1;
 | |
|             UINT32 friendlyNameForced : 1;
 | |
|             UINT32 edidIdsValid : 1;
 | |
|             UINT32 reserved : 29;
 | |
|         } DUMMYSTRUCTNAME;
 | |
|         UINT32 value;
 | |
|     } DUMMYUNIONNAME;
 | |
| } DISPLAYCONFIG_TARGET_DEVICE_NAME_FLAGS;
 | |
| 
 | |
| typedef struct DISPLAYCONFIG_TARGET_DEVICE_NAME
 | |
| {
 | |
|     DISPLAYCONFIG_DEVICE_INFO_HEADER       header;
 | |
|     DISPLAYCONFIG_TARGET_DEVICE_NAME_FLAGS flags;
 | |
|     DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY  outputTechnology;
 | |
|     UINT16                                 edidManufactureId;
 | |
|     UINT16                                 edidProductCodeId;
 | |
|     UINT32                                 connectorInstance;
 | |
|     WCHAR                                  monitorFriendlyDeviceName[64];
 | |
|     WCHAR                                  monitorDevicePath[128];
 | |
| } DISPLAYCONFIG_TARGET_DEVICE_NAME;
 | |
| 
 | |
| typedef enum DISPLAYCONFIG_TOPOLOGY_ID
 | |
| {
 | |
|     DISPLAYCONFIG_TOPOLOGY_INTERNAL = 0x00000001,
 | |
|     DISPLAYCONFIG_TOPOLOGY_CLONE = 0x00000002,
 | |
|     DISPLAYCONFIG_TOPOLOGY_EXTEND = 0x00000004,
 | |
|     DISPLAYCONFIG_TOPOLOGY_EXTERNAL = 0x00000008,
 | |
|     DISPLAYCONFIG_TOPOLOGY_FORCE_UINT32 = 0xFFFFFFFF
 | |
| } DISPLAYCONFIG_TOPOLOGY_ID;
 | |
| 
 | |
| #endif //#if WINVER < 0x0601
 | |
| 
 | |
| typedef LONG (*pGetDisplayConfigBufferSizes)(UINT32 flags, UINT32 *numPathArrayElements, UINT32 *numModeInfoArrayElements);
 | |
| typedef LONG (*pQueryDisplayConfig)(UINT32 flags, UINT32 *numPathArrayElements, DISPLAYCONFIG_PATH_INFO *pathArray, UINT32 *numModeInfoArrayElements, DISPLAYCONFIG_MODE_INFO *modeInfoArray, DISPLAYCONFIG_TOPOLOGY_ID *currentTopologyId);
 | |
| typedef LONG (*pDisplayConfigGetDeviceInfo)(DISPLAYCONFIG_DEVICE_INFO_HEADER* requestPacket);
 | |
| 
 | |
| typedef struct AccurateMonitorNameRequiredData
 | |
| {
 | |
|     HMODULE m_dll;
 | |
|     pGetDisplayConfigBufferSizes m_GetDisplayConfigBufferSizes;
 | |
|     pQueryDisplayConfig m_QueryDisplayConfig;
 | |
|     pDisplayConfigGetDeviceInfo m_DisplayConfigGetDeviceInfo;
 | |
| } AccurateMonitorNameRequiredData;
 | |
| 
 | |
| BOOL loadWin7MonitorPointers(AccurateMonitorNameRequiredData *io_ptrs)
 | |
| {
 | |
|     if(!IsWindows7OrGreater())
 | |
|         return 0;
 | |
| 
 | |
|     io_ptrs->m_dll = LoadLibrary(L"User32.dll");
 | |
|     if (io_ptrs == NULL)
 | |
|         return 0;
 | |
| 
 | |
|     io_ptrs->m_GetDisplayConfigBufferSizes = (pGetDisplayConfigBufferSizes)GetProcAddress(io_ptrs->m_dll, "GetDisplayConfigBufferSizes");
 | |
|     if(io_ptrs->m_GetDisplayConfigBufferSizes == NULL)
 | |
|         return 0;
 | |
| 
 | |
|     io_ptrs->m_QueryDisplayConfig = (pQueryDisplayConfig)GetProcAddress(io_ptrs->m_dll, "QueryDisplayConfig");
 | |
|     if(io_ptrs->m_QueryDisplayConfig == NULL)
 | |
|         return 0;
 | |
| 
 | |
|     io_ptrs->m_DisplayConfigGetDeviceInfo = (pDisplayConfigGetDeviceInfo)GetProcAddress(io_ptrs->m_dll, "DisplayConfigGetDeviceInfo");
 | |
|     if(io_ptrs->m_DisplayConfigGetDeviceInfo == NULL)
 | |
|         return 0;
 | |
| 
 | |
|     return 1;
 | |
| }
 | |
| 
 | |
| // If the returned pointer is valid (not NULL) the caller of this function is in charge of freeing the memory when he is done.
 | |
| static char * GetAccurateMonitorName(const WCHAR *deviceName)
 | |
| {
 | |
|     AccurateMonitorNameRequiredData dllPointers;
 | |
|     if(loadWin7MonitorPointers(&dllPointers) == 0)
 | |
|         return NULL;
 | |
| 
 | |
|     DISPLAYCONFIG_PATH_INFO *paths;
 | |
|     paths = NULL;
 | |
|     DISPLAYCONFIG_MODE_INFO *modes;
 | |
|     modes = NULL;
 | |
|     char *retval;
 | |
|     retval = NULL;
 | |
|     UINT32 pathCount;
 | |
|     pathCount = 0;
 | |
|     UINT32 modeCount;
 | |
|     modeCount = 0;
 | |
|     UINT32 i;
 | |
|     LONG rc;
 | |
| 
 | |
|     do {
 | |
|         rc = dllPointers.m_GetDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS, &pathCount, &modeCount);
 | |
|         if (rc != ERROR_SUCCESS) {
 | |
|             goto GET_ACCURATE_MONITOR_NAME_FAILURE;
 | |
|         }
 | |
| 
 | |
|         free(paths);
 | |
|         free(modes);
 | |
| 
 | |
|         paths = (DISPLAYCONFIG_PATH_INFO *) malloc(sizeof (DISPLAYCONFIG_PATH_INFO) * pathCount);
 | |
|         modes = (DISPLAYCONFIG_MODE_INFO *) malloc(sizeof (DISPLAYCONFIG_MODE_INFO) * modeCount);
 | |
|         if ((paths == NULL) || (modes == NULL)) {
 | |
|             goto GET_ACCURATE_MONITOR_NAME_FAILURE;
 | |
|         }
 | |
| 
 | |
|         rc = dllPointers.m_QueryDisplayConfig(QDC_ONLY_ACTIVE_PATHS, &pathCount, paths, &modeCount, modes, 0);
 | |
|     } while (rc == ERROR_INSUFFICIENT_BUFFER);
 | |
| 
 | |
|     if (rc == ERROR_SUCCESS) {
 | |
|         for (i = 0; i < pathCount; i++) {
 | |
|             DISPLAYCONFIG_SOURCE_DEVICE_NAME sourceName;
 | |
|             DISPLAYCONFIG_TARGET_DEVICE_NAME targetName;
 | |
| 
 | |
|             ZeroMemory(&sourceName, sizeof(sourceName));
 | |
|             sourceName.header.adapterId = paths[i].targetInfo.adapterId;
 | |
|             sourceName.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME;
 | |
|             sourceName.header.size = sizeof (sourceName);
 | |
|             sourceName.header.id = paths[i].sourceInfo.id;
 | |
|             rc = dllPointers.m_DisplayConfigGetDeviceInfo(&sourceName.header);
 | |
|             if (rc != ERROR_SUCCESS) {
 | |
|                 break;
 | |
|             } else if (wcscmp(deviceName, sourceName.viewGdiDeviceName) != 0) {
 | |
|                 continue;
 | |
|             }
 | |
| 
 | |
|             ZeroMemory(&targetName, sizeof(targetName));
 | |
|             targetName.header.adapterId = paths[i].targetInfo.adapterId;
 | |
|             targetName.header.id = paths[i].targetInfo.id;
 | |
|             targetName.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME;
 | |
|             targetName.header.size = sizeof (targetName);
 | |
|             rc = dllPointers.m_DisplayConfigGetDeviceInfo(&targetName.header);
 | |
|             if (rc == ERROR_SUCCESS) {
 | |
|                 retval = _glfwCreateUTF8FromWideStringWin32(targetName.monitorFriendlyDeviceName);
 | |
|                 /* if we got an empty string, treat it as failure so we'll fallback
 | |
|                    to getting the generic name. */
 | |
|                 if (retval && (*retval == '\0')) {
 | |
|                     free(retval);
 | |
|                     retval = NULL;
 | |
|                 }
 | |
|             }
 | |
|             break;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     FreeLibrary(dllPointers.m_dll);
 | |
|     free(paths);
 | |
|     free(modes);
 | |
|     return retval;
 | |
| 
 | |
| GET_ACCURATE_MONITOR_NAME_FAILURE:
 | |
|     FreeLibrary(dllPointers.m_dll);
 | |
|     free(retval);
 | |
|     free(paths);
 | |
|     free(modes);
 | |
|     return NULL;
 | |
| }
 | |
| 
 | |
| 
 | |
| // Callback for EnumDisplayMonitors in createMonitor
 | |
| //
 | |
| static BOOL CALLBACK monitorCallback(HMONITOR handle,
 | |
|                                      HDC dc,
 | |
|                                      RECT* rect,
 | |
|                                      LPARAM data)
 | |
| {
 | |
|     MONITORINFOEXW mi;
 | |
|     ZeroMemory(&mi, sizeof(mi));
 | |
|     mi.cbSize = sizeof(mi);
 | |
| 
 | |
|     if (GetMonitorInfoW(handle, (MONITORINFO*) &mi))
 | |
|     {
 | |
|         _GLFWmonitor* monitor = (_GLFWmonitor*) data;
 | |
|         if (wcscmp(mi.szDevice, monitor->win32.adapterName) == 0)
 | |
|         {
 | |
|             monitor->win32.handle = handle;
 | |
|             char *possiblyMoreAccurateMonitorName;
 | |
|             possiblyMoreAccurateMonitorName = GetAccurateMonitorName(mi.szDevice);
 | |
|             if(possiblyMoreAccurateMonitorName != NULL)
 | |
|             {
 | |
|                 strncpy(monitor->name, possiblyMoreAccurateMonitorName, sizeof(monitor->name) - 1);
 | |
|                 free(possiblyMoreAccurateMonitorName);
 | |
|                 possiblyMoreAccurateMonitorName = NULL;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     return TRUE;
 | |
| }
 | |
| 
 | |
| // Create monitor from an adapter and (optionally) a display
 | |
| //
 | |
| static _GLFWmonitor* createMonitor(DISPLAY_DEVICEW* adapter,
 | |
|                                    DISPLAY_DEVICEW* display)
 | |
| {
 | |
|     _GLFWmonitor* monitor;
 | |
|     int widthMM, heightMM;
 | |
|     char* name;
 | |
|     HDC dc;
 | |
|     DEVMODEW dm;
 | |
|     RECT rect;
 | |
| 
 | |
|     if (display)
 | |
|         name = _glfwCreateUTF8FromWideStringWin32(display->DeviceString);
 | |
|     else
 | |
|         name = _glfwCreateUTF8FromWideStringWin32(adapter->DeviceString);
 | |
|     if (!name)
 | |
|         return NULL;
 | |
| 
 | |
|     ZeroMemory(&dm, sizeof(dm));
 | |
|     dm.dmSize = sizeof(dm);
 | |
|     EnumDisplaySettingsW(adapter->DeviceName, ENUM_CURRENT_SETTINGS, &dm);
 | |
| 
 | |
|     dc = CreateDCW(L"DISPLAY", adapter->DeviceName, NULL, NULL);
 | |
| 
 | |
|     if (IsWindows8Point1OrGreater())
 | |
|     {
 | |
|         widthMM  = GetDeviceCaps(dc, HORZSIZE);
 | |
|         heightMM = GetDeviceCaps(dc, VERTSIZE);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         widthMM  = (int) (dm.dmPelsWidth * 25.4f / GetDeviceCaps(dc, LOGPIXELSX));
 | |
|         heightMM = (int) (dm.dmPelsHeight * 25.4f / GetDeviceCaps(dc, LOGPIXELSY));
 | |
|     }
 | |
| 
 | |
|     DeleteDC(dc);
 | |
| 
 | |
|     monitor = _glfwAllocMonitor(name, widthMM, heightMM);
 | |
|     _glfw_free(name);
 | |
| 
 | |
|     if (adapter->StateFlags & DISPLAY_DEVICE_MODESPRUNED)
 | |
|         monitor->win32.modesPruned = GLFW_TRUE;
 | |
| 
 | |
|     wcscpy(monitor->win32.adapterName, adapter->DeviceName);
 | |
|     WideCharToMultiByte(CP_UTF8, 0,
 | |
|                         adapter->DeviceName, -1,
 | |
|                         monitor->win32.publicAdapterName,
 | |
|                         sizeof(monitor->win32.publicAdapterName),
 | |
|                         NULL, NULL);
 | |
| 
 | |
|     if (display)
 | |
|     {
 | |
|         wcscpy(monitor->win32.displayName, display->DeviceName);
 | |
|         WideCharToMultiByte(CP_UTF8, 0,
 | |
|                             display->DeviceName, -1,
 | |
|                             monitor->win32.publicDisplayName,
 | |
|                             sizeof(monitor->win32.publicDisplayName),
 | |
|                             NULL, NULL);
 | |
|     }
 | |
| 
 | |
|     rect.left   = dm.dmPosition.x;
 | |
|     rect.top    = dm.dmPosition.y;
 | |
|     rect.right  = dm.dmPosition.x + dm.dmPelsWidth;
 | |
|     rect.bottom = dm.dmPosition.y + dm.dmPelsHeight;
 | |
| 
 | |
|     EnumDisplayMonitors(NULL, &rect, monitorCallback, (LPARAM) monitor);
 | |
|     return monitor;
 | |
| }
 | |
| 
 | |
| 
 | |
| //////////////////////////////////////////////////////////////////////////
 | |
| //////                       GLFW internal API                      //////
 | |
| //////////////////////////////////////////////////////////////////////////
 | |
| 
 | |
| // Poll for changes in the set of connected monitors
 | |
| //
 | |
| void _glfwPollMonitorsWin32(void)
 | |
| {
 | |
|     int i, disconnectedCount;
 | |
|     _GLFWmonitor** disconnected = NULL;
 | |
|     DWORD adapterIndex, displayIndex;
 | |
|     DISPLAY_DEVICEW adapter, display;
 | |
|     _GLFWmonitor* monitor;
 | |
| 
 | |
|     disconnectedCount = _glfw.monitorCount;
 | |
|     if (disconnectedCount)
 | |
|     {
 | |
|         disconnected = _glfw_calloc(_glfw.monitorCount, sizeof(_GLFWmonitor*));
 | |
|         memcpy(disconnected,
 | |
|                _glfw.monitors,
 | |
|                _glfw.monitorCount * sizeof(_GLFWmonitor*));
 | |
|     }
 | |
| 
 | |
|     for (adapterIndex = 0;  ;  adapterIndex++)
 | |
|     {
 | |
|         int type = _GLFW_INSERT_LAST;
 | |
| 
 | |
|         ZeroMemory(&adapter, sizeof(adapter));
 | |
|         adapter.cb = sizeof(adapter);
 | |
| 
 | |
|         if (!EnumDisplayDevicesW(NULL, adapterIndex, &adapter, 0))
 | |
|             break;
 | |
| 
 | |
|         if (!(adapter.StateFlags & DISPLAY_DEVICE_ACTIVE))
 | |
|             continue;
 | |
| 
 | |
|         if (adapter.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)
 | |
|             type = _GLFW_INSERT_FIRST;
 | |
| 
 | |
|         for (displayIndex = 0;  ;  displayIndex++)
 | |
|         {
 | |
|             ZeroMemory(&display, sizeof(display));
 | |
|             display.cb = sizeof(display);
 | |
| 
 | |
|             if (!EnumDisplayDevicesW(adapter.DeviceName, displayIndex, &display, 0))
 | |
|                 break;
 | |
| 
 | |
|             if (!(display.StateFlags & DISPLAY_DEVICE_ACTIVE))
 | |
|                 continue;
 | |
| 
 | |
|             for (i = 0;  i < disconnectedCount;  i++)
 | |
|             {
 | |
|                 if (disconnected[i] &&
 | |
|                     wcscmp(disconnected[i]->win32.displayName,
 | |
|                            display.DeviceName) == 0)
 | |
|                 {
 | |
|                     disconnected[i] = NULL;
 | |
|                     // handle may have changed, update
 | |
|                     EnumDisplayMonitors(NULL, NULL, monitorCallback, (LPARAM) _glfw.monitors[i]);
 | |
|                     break;
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             if (i < disconnectedCount)
 | |
|                 continue;
 | |
| 
 | |
|             monitor = createMonitor(&adapter, &display);
 | |
|             if (!monitor)
 | |
|             {
 | |
|                 _glfw_free(disconnected);
 | |
|                 return;
 | |
|             }
 | |
| 
 | |
|             _glfwInputMonitor(monitor, GLFW_CONNECTED, type);
 | |
| 
 | |
|             type = _GLFW_INSERT_LAST;
 | |
|         }
 | |
| 
 | |
|         // HACK: If an active adapter does not have any display devices
 | |
|         //       (as sometimes happens), add it directly as a monitor
 | |
|         if (displayIndex == 0)
 | |
|         {
 | |
|             for (i = 0;  i < disconnectedCount;  i++)
 | |
|             {
 | |
|                 if (disconnected[i] &&
 | |
|                     wcscmp(disconnected[i]->win32.adapterName,
 | |
|                            adapter.DeviceName) == 0)
 | |
|                 {
 | |
|                     disconnected[i] = NULL;
 | |
|                     break;
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             if (i < disconnectedCount)
 | |
|                 continue;
 | |
| 
 | |
|             monitor = createMonitor(&adapter, NULL);
 | |
|             if (!monitor)
 | |
|             {
 | |
|                 _glfw_free(disconnected);
 | |
|                 return;
 | |
|             }
 | |
| 
 | |
|             _glfwInputMonitor(monitor, GLFW_CONNECTED, type);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     for (i = 0;  i < disconnectedCount;  i++)
 | |
|     {
 | |
|         if (disconnected[i])
 | |
|             _glfwInputMonitor(disconnected[i], GLFW_DISCONNECTED, 0);
 | |
|     }
 | |
| 
 | |
|     _glfw_free(disconnected);
 | |
| }
 | |
| 
 | |
| // Change the current video mode
 | |
| //
 | |
| void _glfwSetVideoModeWin32(_GLFWmonitor* monitor, const GLFWvidmode* desired)
 | |
| {
 | |
|     GLFWvidmode current;
 | |
|     const GLFWvidmode* best;
 | |
|     DEVMODEW dm;
 | |
|     LONG result;
 | |
| 
 | |
|     best = _glfwChooseVideoMode(monitor, desired);
 | |
|     _glfwGetVideoModeWin32(monitor, ¤t);
 | |
|     if (_glfwCompareVideoModes(¤t, best) == 0)
 | |
|         return;
 | |
| 
 | |
|     ZeroMemory(&dm, sizeof(dm));
 | |
|     dm.dmSize = sizeof(dm);
 | |
|     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;
 | |
| 
 | |
|     result = ChangeDisplaySettingsExW(monitor->win32.adapterName,
 | |
|                                       &dm,
 | |
|                                       NULL,
 | |
|                                       CDS_FULLSCREEN,
 | |
|                                       NULL);
 | |
|     if (result == DISP_CHANGE_SUCCESSFUL)
 | |
|         monitor->win32.modeChanged = GLFW_TRUE;
 | |
|     else
 | |
|     {
 | |
|         const char* description = "Unknown error";
 | |
| 
 | |
|         if (result == DISP_CHANGE_BADDUALVIEW)
 | |
|             description = "The system uses DualView";
 | |
|         else if (result == DISP_CHANGE_BADFLAGS)
 | |
|             description = "Invalid flags";
 | |
|         else if (result == DISP_CHANGE_BADMODE)
 | |
|             description = "Graphics mode not supported";
 | |
|         else if (result == DISP_CHANGE_BADPARAM)
 | |
|             description = "Invalid parameter";
 | |
|         else if (result == DISP_CHANGE_FAILED)
 | |
|             description = "Graphics mode failed";
 | |
|         else if (result == DISP_CHANGE_NOTUPDATED)
 | |
|             description = "Failed to write to registry";
 | |
|         else if (result == DISP_CHANGE_RESTART)
 | |
|             description = "Computer restart required";
 | |
| 
 | |
|         _glfwInputError(GLFW_PLATFORM_ERROR,
 | |
|                         "Win32: Failed to set video mode: %s",
 | |
|                         description);
 | |
|     }
 | |
| }
 | |
| 
 | |
| // Restore the previously saved (original) video mode
 | |
| //
 | |
| void _glfwRestoreVideoModeWin32(_GLFWmonitor* monitor)
 | |
| {
 | |
|     if (monitor->win32.modeChanged)
 | |
|     {
 | |
|         ChangeDisplaySettingsExW(monitor->win32.adapterName,
 | |
|                                  NULL, NULL, CDS_FULLSCREEN, NULL);
 | |
|         monitor->win32.modeChanged = GLFW_FALSE;
 | |
|     }
 | |
| }
 | |
| 
 | |
| void _glfwGetHMONITORContentScaleWin32(HMONITOR handle, float* xscale, float* yscale)
 | |
| {
 | |
|     UINT xdpi, ydpi;
 | |
| 
 | |
|     if (xscale)
 | |
|         *xscale = 0.f;
 | |
|     if (yscale)
 | |
|         *yscale = 0.f;
 | |
| 
 | |
|     if (IsWindows8Point1OrGreater())
 | |
|     {
 | |
|         if (GetDpiForMonitor(handle, MDT_EFFECTIVE_DPI, &xdpi, &ydpi) != S_OK)
 | |
|         {
 | |
|             _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to query monitor DPI");
 | |
|             return;
 | |
|         }
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         const HDC dc = GetDC(NULL);
 | |
|         xdpi = GetDeviceCaps(dc, LOGPIXELSX);
 | |
|         ydpi = GetDeviceCaps(dc, LOGPIXELSY);
 | |
|         ReleaseDC(NULL, dc);
 | |
|     }
 | |
| 
 | |
|     if (xscale)
 | |
|         *xscale = xdpi / (float) USER_DEFAULT_SCREEN_DPI;
 | |
|     if (yscale)
 | |
|         *yscale = ydpi / (float) USER_DEFAULT_SCREEN_DPI;
 | |
| }
 | |
| 
 | |
| 
 | |
| //////////////////////////////////////////////////////////////////////////
 | |
| //////                       GLFW platform API                      //////
 | |
| //////////////////////////////////////////////////////////////////////////
 | |
| 
 | |
| void _glfwFreeMonitorWin32(_GLFWmonitor* monitor)
 | |
| {
 | |
| }
 | |
| 
 | |
| void _glfwGetMonitorPosWin32(_GLFWmonitor* monitor, int* xpos, int* ypos)
 | |
| {
 | |
|     DEVMODEW dm;
 | |
|     ZeroMemory(&dm, sizeof(dm));
 | |
|     dm.dmSize = sizeof(dm);
 | |
| 
 | |
|     EnumDisplaySettingsExW(monitor->win32.adapterName,
 | |
|                            ENUM_CURRENT_SETTINGS,
 | |
|                            &dm,
 | |
|                            EDS_ROTATEDMODE);
 | |
| 
 | |
|     if (xpos)
 | |
|         *xpos = dm.dmPosition.x;
 | |
|     if (ypos)
 | |
|         *ypos = dm.dmPosition.y;
 | |
| }
 | |
| 
 | |
| void _glfwGetMonitorContentScaleWin32(_GLFWmonitor* monitor,
 | |
|                                       float* xscale, float* yscale)
 | |
| {
 | |
|     _glfwGetHMONITORContentScaleWin32(monitor->win32.handle, xscale, yscale);
 | |
| }
 | |
| 
 | |
| void _glfwGetMonitorWorkareaWin32(_GLFWmonitor* monitor,
 | |
|                                   int* xpos, int* ypos,
 | |
|                                   int* width, int* height)
 | |
| {
 | |
|     MONITORINFO mi = { sizeof(mi) };
 | |
|     GetMonitorInfoW(monitor->win32.handle, &mi);
 | |
| 
 | |
|     if (xpos)
 | |
|         *xpos = mi.rcWork.left;
 | |
|     if (ypos)
 | |
|         *ypos = mi.rcWork.top;
 | |
|     if (width)
 | |
|         *width = mi.rcWork.right - mi.rcWork.left;
 | |
|     if (height)
 | |
|         *height = mi.rcWork.bottom - mi.rcWork.top;
 | |
| }
 | |
| 
 | |
| GLFWvidmode* _glfwGetVideoModesWin32(_GLFWmonitor* monitor, int* count)
 | |
| {
 | |
|     int modeIndex = 0, size = 0;
 | |
|     GLFWvidmode* result = NULL;
 | |
| 
 | |
|     *count = 0;
 | |
| 
 | |
|     for (;;)
 | |
|     {
 | |
|         int i;
 | |
|         GLFWvidmode mode;
 | |
|         DEVMODEW dm;
 | |
| 
 | |
|         ZeroMemory(&dm, sizeof(dm));
 | |
|         dm.dmSize = sizeof(dm);
 | |
| 
 | |
|         if (!EnumDisplaySettingsW(monitor->win32.adapterName, modeIndex, &dm))
 | |
|             break;
 | |
| 
 | |
|         modeIndex++;
 | |
| 
 | |
|         // Skip modes with less than 15 BPP
 | |
|         if (dm.dmBitsPerPel < 15)
 | |
|             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 < *count;  i++)
 | |
|         {
 | |
|             if (_glfwCompareVideoModes(result + i, &mode) == 0)
 | |
|                 break;
 | |
|         }
 | |
| 
 | |
|         // Skip duplicate modes
 | |
|         if (i < *count)
 | |
|             continue;
 | |
| 
 | |
|         if (monitor->win32.modesPruned)
 | |
|         {
 | |
|             // Skip modes not supported by the connected displays
 | |
|             if (ChangeDisplaySettingsExW(monitor->win32.adapterName,
 | |
|                                          &dm,
 | |
|                                          NULL,
 | |
|                                          CDS_TEST,
 | |
|                                          NULL) != DISP_CHANGE_SUCCESSFUL)
 | |
|             {
 | |
|                 continue;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         if (*count == size)
 | |
|         {
 | |
|             size += 128;
 | |
|             result = (GLFWvidmode*) _glfw_realloc(result, size * sizeof(GLFWvidmode));
 | |
|         }
 | |
| 
 | |
|         (*count)++;
 | |
|         result[*count - 1] = mode;
 | |
|     }
 | |
| 
 | |
|     if (!*count)
 | |
|     {
 | |
|         // HACK: Report the current mode if no valid modes were found
 | |
|         result = _glfw_calloc(1, sizeof(GLFWvidmode));
 | |
|         _glfwGetVideoModeWin32(monitor, result);
 | |
|         *count = 1;
 | |
|     }
 | |
| 
 | |
|     return result;
 | |
| }
 | |
| 
 | |
| void _glfwGetVideoModeWin32(_GLFWmonitor* monitor, GLFWvidmode* mode)
 | |
| {
 | |
|     DEVMODEW dm;
 | |
|     ZeroMemory(&dm, sizeof(dm));
 | |
|     dm.dmSize = sizeof(dm);
 | |
| 
 | |
|     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);
 | |
| }
 | |
| 
 | |
| GLFWbool _glfwGetGammaRampWin32(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
 | |
| {
 | |
|     HDC dc;
 | |
|     WORD values[3][256];
 | |
| 
 | |
|     dc = CreateDCW(L"DISPLAY", monitor->win32.adapterName, NULL, NULL);
 | |
|     GetDeviceGammaRamp(dc, values);
 | |
|     DeleteDC(dc);
 | |
| 
 | |
|     _glfwAllocGammaArrays(ramp, 256);
 | |
| 
 | |
|     memcpy(ramp->red,   values[0], sizeof(values[0]));
 | |
|     memcpy(ramp->green, values[1], sizeof(values[1]));
 | |
|     memcpy(ramp->blue,  values[2], sizeof(values[2]));
 | |
| 
 | |
|     return GLFW_TRUE;
 | |
| }
 | |
| 
 | |
| void _glfwSetGammaRampWin32(_GLFWmonitor* monitor, const GLFWgammaramp* ramp)
 | |
| {
 | |
|     HDC dc;
 | |
|     WORD values[3][256];
 | |
| 
 | |
|     if (ramp->size != 256)
 | |
|     {
 | |
|         _glfwInputError(GLFW_PLATFORM_ERROR,
 | |
|                         "Win32: Gamma ramp size must be 256");
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     memcpy(values[0], ramp->red,   sizeof(values[0]));
 | |
|     memcpy(values[1], ramp->green, sizeof(values[1]));
 | |
|     memcpy(values[2], ramp->blue,  sizeof(values[2]));
 | |
| 
 | |
|     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;
 | |
| }
 | |
| 
 | |
| #endif // _GLFW_WIN32
 | |
| 
 |