medfall

A super great game engine
Log | Files | Refs

win32_monitor.cc (13667B)


      1 //========================================================================
      2 // GLFW 3.3 Win32 - www.glfw.org
      3 //------------------------------------------------------------------------
      4 // Copyright (c) 2002-2006 Marcus Geelnard
      5 // Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
      6 //
      7 // This software is provided 'as-is', without any express or implied
      8 // warranty. In no event will the authors be held liable for any damages
      9 // arising from the use of this software.
     10 //
     11 // Permission is granted to anyone to use this software for any purpose,
     12 // including commercial applications, and to alter it and redistribute it
     13 // freely, subject to the following restrictions:
     14 //
     15 // 1. The origin of this software must not be misrepresented; you must not
     16 //    claim that you wrote the original software. If you use this software
     17 //    in a product, an acknowledgment in the product documentation would
     18 //    be appreciated but is not required.
     19 //
     20 // 2. Altered source versions must be plainly marked as such, and must not
     21 //    be misrepresented as being the original software.
     22 //
     23 // 3. This notice may not be removed or altered from any source
     24 //    distribution.
     25 //
     26 //========================================================================
     27 
     28 #include "internal.h"
     29 
     30 #include <stdlib.h>
     31 #include <string.h>
     32 #include <limits.h>
     33 #include <malloc.h>
     34 
     35 
     36 // Create monitor from an adapter and (optionally) a display
     37 //
     38 static _GLFWmonitor* createMonitor(DISPLAY_DEVICEW* adapter,
     39                                    DISPLAY_DEVICEW* display)
     40 {
     41     _GLFWmonitor* monitor;
     42     char* name;
     43     HDC dc;
     44 
     45     if (display)
     46         name = _glfwCreateUTF8FromWideStringWin32(display->DeviceString);
     47     else
     48         name = _glfwCreateUTF8FromWideStringWin32(adapter->DeviceString);
     49     if (!name)
     50         return NULL;
     51 
     52     dc = CreateDCW(L"DISPLAY", adapter->DeviceName, NULL, NULL);
     53 
     54     monitor = _glfwAllocMonitor(name,
     55                                 GetDeviceCaps(dc, HORZSIZE),
     56                                 GetDeviceCaps(dc, VERTSIZE));
     57 
     58     DeleteDC(dc);
     59     free(name);
     60 
     61     if (adapter->StateFlags & DISPLAY_DEVICE_MODESPRUNED)
     62         monitor->win32.modesPruned = GLFW_TRUE;
     63 
     64     wcscpy(monitor->win32.adapterName, adapter->DeviceName);
     65     WideCharToMultiByte(CP_UTF8, 0,
     66                         adapter->DeviceName, -1,
     67                         monitor->win32.publicAdapterName,
     68                         sizeof(monitor->win32.publicAdapterName),
     69                         NULL, NULL);
     70 
     71     if (display)
     72     {
     73         wcscpy(monitor->win32.displayName, display->DeviceName);
     74         WideCharToMultiByte(CP_UTF8, 0,
     75                             display->DeviceName, -1,
     76                             monitor->win32.publicDisplayName,
     77                             sizeof(monitor->win32.publicDisplayName),
     78                             NULL, NULL);
     79     }
     80 
     81     return monitor;
     82 }
     83 
     84 
     85 //////////////////////////////////////////////////////////////////////////
     86 //////                       GLFW internal API                      //////
     87 //////////////////////////////////////////////////////////////////////////
     88 
     89 // Poll for changes in the set of connected monitors
     90 //
     91 void _glfwPollMonitorsWin32(void)
     92 {
     93     int i, disconnectedCount;
     94     _GLFWmonitor** disconnected = NULL;
     95     DWORD adapterIndex, displayIndex;
     96     DISPLAY_DEVICEW adapter, display;
     97     _GLFWmonitor* monitor;
     98 
     99     disconnectedCount = _glfw.monitorCount;
    100     if (disconnectedCount)
    101     {
    102         disconnected = calloc(_glfw.monitorCount, sizeof(_GLFWmonitor*));
    103         memcpy(disconnected,
    104                _glfw.monitors,
    105                _glfw.monitorCount * sizeof(_GLFWmonitor*));
    106     }
    107 
    108     for (adapterIndex = 0;  ;  adapterIndex++)
    109     {
    110         int type = _GLFW_INSERT_LAST;
    111 
    112         ZeroMemory(&adapter, sizeof(DISPLAY_DEVICEW));
    113         adapter.cb = sizeof(DISPLAY_DEVICEW);
    114 
    115         if (!EnumDisplayDevicesW(NULL, adapterIndex, &adapter, 0))
    116             break;
    117 
    118         if (!(adapter.StateFlags & DISPLAY_DEVICE_ACTIVE))
    119             continue;
    120 
    121         if (adapter.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)
    122             type = _GLFW_INSERT_FIRST;
    123 
    124         for (displayIndex = 0;  ;  displayIndex++)
    125         {
    126             ZeroMemory(&display, sizeof(DISPLAY_DEVICEW));
    127             display.cb = sizeof(DISPLAY_DEVICEW);
    128 
    129             if (!EnumDisplayDevicesW(adapter.DeviceName, displayIndex, &display, 0))
    130                 break;
    131 
    132             if (!(display.StateFlags & DISPLAY_DEVICE_ACTIVE))
    133                 continue;
    134 
    135             for (i = 0;  i < disconnectedCount;  i++)
    136             {
    137                 if (disconnected[i] &&
    138                     wcscmp(disconnected[i]->win32.displayName,
    139                            display.DeviceName) == 0)
    140                 {
    141                     disconnected[i] = NULL;
    142                     break;
    143                 }
    144             }
    145 
    146             if (i < disconnectedCount)
    147                 continue;
    148 
    149             monitor = createMonitor(&adapter, &display);
    150             if (!monitor)
    151             {
    152                 free(disconnected);
    153                 return;
    154             }
    155 
    156             _glfwInputMonitor(monitor, GLFW_CONNECTED, type);
    157 
    158             type = _GLFW_INSERT_LAST;
    159         }
    160 
    161         // HACK: If an active adapter does not have any display devices
    162         //       (as sometimes happens), add it directly as a monitor
    163         if (displayIndex == 0)
    164         {
    165             for (i = 0;  i < disconnectedCount;  i++)
    166             {
    167                 if (disconnected[i] &&
    168                     wcscmp(disconnected[i]->win32.adapterName,
    169                            adapter.DeviceName) == 0)
    170                 {
    171                     disconnected[i] = NULL;
    172                     break;
    173                 }
    174             }
    175 
    176             if (i < disconnectedCount)
    177                 continue;
    178 
    179             monitor = createMonitor(&adapter, NULL);
    180             if (!monitor)
    181             {
    182                 free(disconnected);
    183                 return;
    184             }
    185 
    186             _glfwInputMonitor(monitor, GLFW_CONNECTED, type);
    187         }
    188     }
    189 
    190     for (i = 0;  i < disconnectedCount;  i++)
    191     {
    192         if (disconnected[i])
    193             _glfwInputMonitor(disconnected[i], GLFW_DISCONNECTED, 0);
    194     }
    195 
    196     free(disconnected);
    197 }
    198 
    199 // Change the current video mode
    200 //
    201 GLFWbool _glfwSetVideoModeWin32(_GLFWmonitor* monitor, const GLFWvidmode* desired)
    202 {
    203     GLFWvidmode current;
    204     const GLFWvidmode* best;
    205     DEVMODEW dm;
    206     LONG result;
    207 
    208     best = _glfwChooseVideoMode(monitor, desired);
    209     _glfwPlatformGetVideoMode(monitor, &current);
    210     if (_glfwCompareVideoModes(&current, best) == 0)
    211         return GLFW_TRUE;
    212 
    213     ZeroMemory(&dm, sizeof(dm));
    214     dm.dmSize = sizeof(DEVMODEW);
    215     dm.dmFields           = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL |
    216                             DM_DISPLAYFREQUENCY;
    217     dm.dmPelsWidth        = best->width;
    218     dm.dmPelsHeight       = best->height;
    219     dm.dmBitsPerPel       = best->redBits + best->greenBits + best->blueBits;
    220     dm.dmDisplayFrequency = best->refreshRate;
    221 
    222     if (dm.dmBitsPerPel < 15 || dm.dmBitsPerPel >= 24)
    223         dm.dmBitsPerPel = 32;
    224 
    225     result = ChangeDisplaySettingsExW(monitor->win32.adapterName,
    226                                       &dm,
    227                                       NULL,
    228                                       CDS_FULLSCREEN,
    229                                       NULL);
    230     if (result != DISP_CHANGE_SUCCESSFUL)
    231     {
    232         const char* description = "Unknown error";
    233 
    234         if (result == DISP_CHANGE_BADDUALVIEW)
    235             description = "The system uses DualView";
    236         else if (result == DISP_CHANGE_BADFLAGS)
    237             description = "Invalid flags";
    238         else if (result == DISP_CHANGE_BADMODE)
    239             description = "Graphics mode not supported";
    240         else if (result == DISP_CHANGE_BADPARAM)
    241             description = "Invalid parameter";
    242         else if (result == DISP_CHANGE_FAILED)
    243             description = "Graphics mode failed";
    244         else if (result == DISP_CHANGE_NOTUPDATED)
    245             description = "Failed to write to registry";
    246         else if (result == DISP_CHANGE_RESTART)
    247             description = "Computer restart required";
    248 
    249         _glfwInputError(GLFW_PLATFORM_ERROR,
    250                         "Win32: Failed to set video mode: %s",
    251                         description);
    252 
    253         return GLFW_FALSE;
    254     }
    255 
    256     monitor->win32.modeChanged = GLFW_TRUE;
    257     return GLFW_TRUE;
    258 }
    259 
    260 // Restore the previously saved (original) video mode
    261 //
    262 void _glfwRestoreVideoModeWin32(_GLFWmonitor* monitor)
    263 {
    264     if (monitor->win32.modeChanged)
    265     {
    266         ChangeDisplaySettingsExW(monitor->win32.adapterName,
    267                                  NULL, NULL, CDS_FULLSCREEN, NULL);
    268         monitor->win32.modeChanged = GLFW_FALSE;
    269     }
    270 }
    271 
    272 
    273 //////////////////////////////////////////////////////////////////////////
    274 //////                       GLFW platform API                      //////
    275 //////////////////////////////////////////////////////////////////////////
    276 
    277 void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos)
    278 {
    279     DEVMODEW settings;
    280     ZeroMemory(&settings, sizeof(DEVMODEW));
    281     settings.dmSize = sizeof(DEVMODEW);
    282 
    283     EnumDisplaySettingsExW(monitor->win32.adapterName,
    284                            ENUM_CURRENT_SETTINGS,
    285                            &settings,
    286                            EDS_ROTATEDMODE);
    287 
    288     if (xpos)
    289         *xpos = settings.dmPosition.x;
    290     if (ypos)
    291         *ypos = settings.dmPosition.y;
    292 }
    293 
    294 GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count)
    295 {
    296     int modeIndex = 0, size = 0;
    297     GLFWvidmode* result = NULL;
    298 
    299     *count = 0;
    300 
    301     for (;;)
    302     {
    303         int i;
    304         GLFWvidmode mode;
    305         DEVMODEW dm;
    306 
    307         ZeroMemory(&dm, sizeof(DEVMODEW));
    308         dm.dmSize = sizeof(DEVMODEW);
    309 
    310         if (!EnumDisplaySettingsW(monitor->win32.adapterName, modeIndex, &dm))
    311             break;
    312 
    313         modeIndex++;
    314 
    315         // Skip modes with less than 15 BPP
    316         if (dm.dmBitsPerPel < 15)
    317             continue;
    318 
    319         mode.width  = dm.dmPelsWidth;
    320         mode.height = dm.dmPelsHeight;
    321         mode.refreshRate = dm.dmDisplayFrequency;
    322         _glfwSplitBPP(dm.dmBitsPerPel,
    323                       &mode.redBits,
    324                       &mode.greenBits,
    325                       &mode.blueBits);
    326 
    327         for (i = 0;  i < *count;  i++)
    328         {
    329             if (_glfwCompareVideoModes(result + i, &mode) == 0)
    330                 break;
    331         }
    332 
    333         // Skip duplicate modes
    334         if (i < *count)
    335             continue;
    336 
    337         if (monitor->win32.modesPruned)
    338         {
    339             // Skip modes not supported by the connected displays
    340             if (ChangeDisplaySettingsExW(monitor->win32.adapterName,
    341                                          &dm,
    342                                          NULL,
    343                                          CDS_TEST,
    344                                          NULL) != DISP_CHANGE_SUCCESSFUL)
    345             {
    346                 continue;
    347             }
    348         }
    349 
    350         if (*count == size)
    351         {
    352             size += 128;
    353             result = (GLFWvidmode*) realloc(result, size * sizeof(GLFWvidmode));
    354         }
    355 
    356         (*count)++;
    357         result[*count - 1] = mode;
    358     }
    359 
    360     if (!*count)
    361     {
    362         // HACK: Report the current mode if no valid modes were found
    363         result = calloc(1, sizeof(GLFWvidmode));
    364         _glfwPlatformGetVideoMode(monitor, result);
    365         *count = 1;
    366     }
    367 
    368     return result;
    369 }
    370 
    371 void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode)
    372 {
    373     DEVMODEW dm;
    374 
    375     ZeroMemory(&dm, sizeof(DEVMODEW));
    376     dm.dmSize = sizeof(DEVMODEW);
    377 
    378     EnumDisplaySettingsW(monitor->win32.adapterName, ENUM_CURRENT_SETTINGS, &dm);
    379 
    380     mode->width  = dm.dmPelsWidth;
    381     mode->height = dm.dmPelsHeight;
    382     mode->refreshRate = dm.dmDisplayFrequency;
    383     _glfwSplitBPP(dm.dmBitsPerPel,
    384                   &mode->redBits,
    385                   &mode->greenBits,
    386                   &mode->blueBits);
    387 }
    388 
    389 void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
    390 {
    391     HDC dc;
    392     WORD values[768];
    393 
    394     dc = CreateDCW(L"DISPLAY", monitor->win32.adapterName, NULL, NULL);
    395     GetDeviceGammaRamp(dc, values);
    396     DeleteDC(dc);
    397 
    398     _glfwAllocGammaArrays(ramp, 256);
    399 
    400     memcpy(ramp->red,   values +   0, 256 * sizeof(unsigned short));
    401     memcpy(ramp->green, values + 256, 256 * sizeof(unsigned short));
    402     memcpy(ramp->blue,  values + 512, 256 * sizeof(unsigned short));
    403 }
    404 
    405 void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp)
    406 {
    407     HDC dc;
    408     WORD values[768];
    409 
    410     if (ramp->size != 256)
    411     {
    412         _glfwInputError(GLFW_PLATFORM_ERROR,
    413                         "Win32: Gamma ramp size must be 256");
    414         return;
    415     }
    416 
    417     memcpy(values +   0, ramp->red,   256 * sizeof(unsigned short));
    418     memcpy(values + 256, ramp->green, 256 * sizeof(unsigned short));
    419     memcpy(values + 512, ramp->blue,  256 * sizeof(unsigned short));
    420 
    421     dc = CreateDCW(L"DISPLAY", monitor->win32.adapterName, NULL, NULL);
    422     SetDeviceGammaRamp(dc, values);
    423     DeleteDC(dc);
    424 }
    425 
    426 
    427 //////////////////////////////////////////////////////////////////////////
    428 //////                        GLFW native API                       //////
    429 //////////////////////////////////////////////////////////////////////////
    430 
    431 GLFWAPI const char* glfwGetWin32Adapter(GLFWmonitor* handle)
    432 {
    433     _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
    434     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
    435     return monitor->win32.publicAdapterName;
    436 }
    437 
    438 GLFWAPI const char* glfwGetWin32Monitor(GLFWmonitor* handle)
    439 {
    440     _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
    441     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
    442     return monitor->win32.publicDisplayName;
    443 }
    444