volviewer

Volumetric Data Toy Viewer
git clone anongit@rnpnr.xyz:volviewer.git
Log | Files | Refs | Feed | LICENSE

win32_monitor.c (16993B)


      1 //========================================================================
      2 // GLFW 3.4 Win32 - www.glfw.org
      3 //------------------------------------------------------------------------
      4 // Copyright (c) 2002-2006 Marcus Geelnard
      5 // Copyright (c) 2006-2019 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 #if defined(_GLFW_WIN32)
     31 
     32 #include <stdlib.h>
     33 #include <string.h>
     34 #include <limits.h>
     35 #include <wchar.h>
     36 
     37 
     38 // Callback for EnumDisplayMonitors in createMonitor
     39 //
     40 static BOOL CALLBACK monitorCallback(HMONITOR handle,
     41                                      HDC dc,
     42                                      RECT* rect,
     43                                      LPARAM data)
     44 {
     45     MONITORINFOEXW mi;
     46     ZeroMemory(&mi, sizeof(mi));
     47     mi.cbSize = sizeof(mi);
     48 
     49     if (GetMonitorInfoW(handle, (MONITORINFO*) &mi))
     50     {
     51         _GLFWmonitor* monitor = (_GLFWmonitor*) data;
     52         if (wcscmp(mi.szDevice, monitor->win32.adapterName) == 0)
     53             monitor->win32.handle = handle;
     54     }
     55 
     56     return TRUE;
     57 }
     58 
     59 // Create monitor from an adapter and (optionally) a display
     60 //
     61 static _GLFWmonitor* createMonitor(DISPLAY_DEVICEW* adapter,
     62                                    DISPLAY_DEVICEW* display)
     63 {
     64     _GLFWmonitor* monitor;
     65     int widthMM, heightMM;
     66     char* name;
     67     HDC dc;
     68     DEVMODEW dm;
     69     RECT rect;
     70 
     71     if (display)
     72         name = _glfwCreateUTF8FromWideStringWin32(display->DeviceString);
     73     else
     74         name = _glfwCreateUTF8FromWideStringWin32(adapter->DeviceString);
     75     if (!name)
     76         return NULL;
     77 
     78     ZeroMemory(&dm, sizeof(dm));
     79     dm.dmSize = sizeof(dm);
     80     EnumDisplaySettingsW(adapter->DeviceName, ENUM_CURRENT_SETTINGS, &dm);
     81 
     82     dc = CreateDCW(L"DISPLAY", adapter->DeviceName, NULL, NULL);
     83 
     84     if (IsWindows8Point1OrGreater())
     85     {
     86         widthMM  = GetDeviceCaps(dc, HORZSIZE);
     87         heightMM = GetDeviceCaps(dc, VERTSIZE);
     88     }
     89     else
     90     {
     91         widthMM  = (int) (dm.dmPelsWidth * 25.4f / GetDeviceCaps(dc, LOGPIXELSX));
     92         heightMM = (int) (dm.dmPelsHeight * 25.4f / GetDeviceCaps(dc, LOGPIXELSY));
     93     }
     94 
     95     DeleteDC(dc);
     96 
     97     monitor = _glfwAllocMonitor(name, widthMM, heightMM);
     98     _glfw_free(name);
     99 
    100     if (adapter->StateFlags & DISPLAY_DEVICE_MODESPRUNED)
    101         monitor->win32.modesPruned = GLFW_TRUE;
    102 
    103     wcscpy(monitor->win32.adapterName, adapter->DeviceName);
    104     WideCharToMultiByte(CP_UTF8, 0,
    105                         adapter->DeviceName, -1,
    106                         monitor->win32.publicAdapterName,
    107                         sizeof(monitor->win32.publicAdapterName),
    108                         NULL, NULL);
    109 
    110     if (display)
    111     {
    112         wcscpy(monitor->win32.displayName, display->DeviceName);
    113         WideCharToMultiByte(CP_UTF8, 0,
    114                             display->DeviceName, -1,
    115                             monitor->win32.publicDisplayName,
    116                             sizeof(monitor->win32.publicDisplayName),
    117                             NULL, NULL);
    118     }
    119 
    120     rect.left   = dm.dmPosition.x;
    121     rect.top    = dm.dmPosition.y;
    122     rect.right  = dm.dmPosition.x + dm.dmPelsWidth;
    123     rect.bottom = dm.dmPosition.y + dm.dmPelsHeight;
    124 
    125     EnumDisplayMonitors(NULL, &rect, monitorCallback, (LPARAM) monitor);
    126     return monitor;
    127 }
    128 
    129 
    130 //////////////////////////////////////////////////////////////////////////
    131 //////                       GLFW internal API                      //////
    132 //////////////////////////////////////////////////////////////////////////
    133 
    134 // Poll for changes in the set of connected monitors
    135 //
    136 void _glfwPollMonitorsWin32(void)
    137 {
    138     int i, disconnectedCount;
    139     _GLFWmonitor** disconnected = NULL;
    140     DWORD adapterIndex, displayIndex;
    141     DISPLAY_DEVICEW adapter, display;
    142     _GLFWmonitor* monitor;
    143 
    144     disconnectedCount = _glfw.monitorCount;
    145     if (disconnectedCount)
    146     {
    147         disconnected = _glfw_calloc(_glfw.monitorCount, sizeof(_GLFWmonitor*));
    148         memcpy(disconnected,
    149                _glfw.monitors,
    150                _glfw.monitorCount * sizeof(_GLFWmonitor*));
    151     }
    152 
    153     for (adapterIndex = 0;  ;  adapterIndex++)
    154     {
    155         int type = _GLFW_INSERT_LAST;
    156 
    157         ZeroMemory(&adapter, sizeof(adapter));
    158         adapter.cb = sizeof(adapter);
    159 
    160         if (!EnumDisplayDevicesW(NULL, adapterIndex, &adapter, 0))
    161             break;
    162 
    163         if (!(adapter.StateFlags & DISPLAY_DEVICE_ACTIVE))
    164             continue;
    165 
    166         if (adapter.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)
    167             type = _GLFW_INSERT_FIRST;
    168 
    169         for (displayIndex = 0;  ;  displayIndex++)
    170         {
    171             ZeroMemory(&display, sizeof(display));
    172             display.cb = sizeof(display);
    173 
    174             if (!EnumDisplayDevicesW(adapter.DeviceName, displayIndex, &display, 0))
    175                 break;
    176 
    177             if (!(display.StateFlags & DISPLAY_DEVICE_ACTIVE))
    178                 continue;
    179 
    180             for (i = 0;  i < disconnectedCount;  i++)
    181             {
    182                 if (disconnected[i] &&
    183                     wcscmp(disconnected[i]->win32.displayName,
    184                            display.DeviceName) == 0)
    185                 {
    186                     disconnected[i] = NULL;
    187                     // handle may have changed, update
    188                     EnumDisplayMonitors(NULL, NULL, monitorCallback, (LPARAM) _glfw.monitors[i]);
    189                     break;
    190                 }
    191             }
    192 
    193             if (i < disconnectedCount)
    194                 continue;
    195 
    196             monitor = createMonitor(&adapter, &display);
    197             if (!monitor)
    198             {
    199                 _glfw_free(disconnected);
    200                 return;
    201             }
    202 
    203             _glfwInputMonitor(monitor, GLFW_CONNECTED, type);
    204 
    205             type = _GLFW_INSERT_LAST;
    206         }
    207 
    208         // HACK: If an active adapter does not have any display devices
    209         //       (as sometimes happens), add it directly as a monitor
    210         if (displayIndex == 0)
    211         {
    212             for (i = 0;  i < disconnectedCount;  i++)
    213             {
    214                 if (disconnected[i] &&
    215                     wcscmp(disconnected[i]->win32.adapterName,
    216                            adapter.DeviceName) == 0)
    217                 {
    218                     disconnected[i] = NULL;
    219                     break;
    220                 }
    221             }
    222 
    223             if (i < disconnectedCount)
    224                 continue;
    225 
    226             monitor = createMonitor(&adapter, NULL);
    227             if (!monitor)
    228             {
    229                 _glfw_free(disconnected);
    230                 return;
    231             }
    232 
    233             _glfwInputMonitor(monitor, GLFW_CONNECTED, type);
    234         }
    235     }
    236 
    237     for (i = 0;  i < disconnectedCount;  i++)
    238     {
    239         if (disconnected[i])
    240             _glfwInputMonitor(disconnected[i], GLFW_DISCONNECTED, 0);
    241     }
    242 
    243     _glfw_free(disconnected);
    244 }
    245 
    246 // Change the current video mode
    247 //
    248 void _glfwSetVideoModeWin32(_GLFWmonitor* monitor, const GLFWvidmode* desired)
    249 {
    250     GLFWvidmode current;
    251     const GLFWvidmode* best;
    252     DEVMODEW dm;
    253     LONG result;
    254 
    255     best = _glfwChooseVideoMode(monitor, desired);
    256     _glfwGetVideoModeWin32(monitor, &current);
    257     if (_glfwCompareVideoModes(&current, best) == 0)
    258         return;
    259 
    260     ZeroMemory(&dm, sizeof(dm));
    261     dm.dmSize = sizeof(dm);
    262     dm.dmFields           = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL |
    263                             DM_DISPLAYFREQUENCY;
    264     dm.dmPelsWidth        = best->width;
    265     dm.dmPelsHeight       = best->height;
    266     dm.dmBitsPerPel       = best->redBits + best->greenBits + best->blueBits;
    267     dm.dmDisplayFrequency = best->refreshRate;
    268 
    269     if (dm.dmBitsPerPel < 15 || dm.dmBitsPerPel >= 24)
    270         dm.dmBitsPerPel = 32;
    271 
    272     result = ChangeDisplaySettingsExW(monitor->win32.adapterName,
    273                                       &dm,
    274                                       NULL,
    275                                       CDS_FULLSCREEN,
    276                                       NULL);
    277     if (result == DISP_CHANGE_SUCCESSFUL)
    278         monitor->win32.modeChanged = GLFW_TRUE;
    279     else
    280     {
    281         const char* description = "Unknown error";
    282 
    283         if (result == DISP_CHANGE_BADDUALVIEW)
    284             description = "The system uses DualView";
    285         else if (result == DISP_CHANGE_BADFLAGS)
    286             description = "Invalid flags";
    287         else if (result == DISP_CHANGE_BADMODE)
    288             description = "Graphics mode not supported";
    289         else if (result == DISP_CHANGE_BADPARAM)
    290             description = "Invalid parameter";
    291         else if (result == DISP_CHANGE_FAILED)
    292             description = "Graphics mode failed";
    293         else if (result == DISP_CHANGE_NOTUPDATED)
    294             description = "Failed to write to registry";
    295         else if (result == DISP_CHANGE_RESTART)
    296             description = "Computer restart required";
    297 
    298         _glfwInputError(GLFW_PLATFORM_ERROR,
    299                         "Win32: Failed to set video mode: %s",
    300                         description);
    301     }
    302 }
    303 
    304 // Restore the previously saved (original) video mode
    305 //
    306 void _glfwRestoreVideoModeWin32(_GLFWmonitor* monitor)
    307 {
    308     if (monitor->win32.modeChanged)
    309     {
    310         ChangeDisplaySettingsExW(monitor->win32.adapterName,
    311                                  NULL, NULL, CDS_FULLSCREEN, NULL);
    312         monitor->win32.modeChanged = GLFW_FALSE;
    313     }
    314 }
    315 
    316 void _glfwGetHMONITORContentScaleWin32(HMONITOR handle, float* xscale, float* yscale)
    317 {
    318     UINT xdpi, ydpi;
    319 
    320     if (xscale)
    321         *xscale = 0.f;
    322     if (yscale)
    323         *yscale = 0.f;
    324 
    325     if (IsWindows8Point1OrGreater())
    326     {
    327         if (GetDpiForMonitor(handle, MDT_EFFECTIVE_DPI, &xdpi, &ydpi) != S_OK)
    328         {
    329             _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to query monitor DPI");
    330             return;
    331         }
    332     }
    333     else
    334     {
    335         const HDC dc = GetDC(NULL);
    336         xdpi = GetDeviceCaps(dc, LOGPIXELSX);
    337         ydpi = GetDeviceCaps(dc, LOGPIXELSY);
    338         ReleaseDC(NULL, dc);
    339     }
    340 
    341     if (xscale)
    342         *xscale = xdpi / (float) USER_DEFAULT_SCREEN_DPI;
    343     if (yscale)
    344         *yscale = ydpi / (float) USER_DEFAULT_SCREEN_DPI;
    345 }
    346 
    347 
    348 //////////////////////////////////////////////////////////////////////////
    349 //////                       GLFW platform API                      //////
    350 //////////////////////////////////////////////////////////////////////////
    351 
    352 void _glfwFreeMonitorWin32(_GLFWmonitor* monitor)
    353 {
    354 }
    355 
    356 void _glfwGetMonitorPosWin32(_GLFWmonitor* monitor, int* xpos, int* ypos)
    357 {
    358     DEVMODEW dm;
    359     ZeroMemory(&dm, sizeof(dm));
    360     dm.dmSize = sizeof(dm);
    361 
    362     EnumDisplaySettingsExW(monitor->win32.adapterName,
    363                            ENUM_CURRENT_SETTINGS,
    364                            &dm,
    365                            EDS_ROTATEDMODE);
    366 
    367     if (xpos)
    368         *xpos = dm.dmPosition.x;
    369     if (ypos)
    370         *ypos = dm.dmPosition.y;
    371 }
    372 
    373 void _glfwGetMonitorContentScaleWin32(_GLFWmonitor* monitor,
    374                                       float* xscale, float* yscale)
    375 {
    376     _glfwGetHMONITORContentScaleWin32(monitor->win32.handle, xscale, yscale);
    377 }
    378 
    379 void _glfwGetMonitorWorkareaWin32(_GLFWmonitor* monitor,
    380                                   int* xpos, int* ypos,
    381                                   int* width, int* height)
    382 {
    383     MONITORINFO mi = { sizeof(mi) };
    384     GetMonitorInfoW(monitor->win32.handle, &mi);
    385 
    386     if (xpos)
    387         *xpos = mi.rcWork.left;
    388     if (ypos)
    389         *ypos = mi.rcWork.top;
    390     if (width)
    391         *width = mi.rcWork.right - mi.rcWork.left;
    392     if (height)
    393         *height = mi.rcWork.bottom - mi.rcWork.top;
    394 }
    395 
    396 GLFWvidmode* _glfwGetVideoModesWin32(_GLFWmonitor* monitor, int* count)
    397 {
    398     int modeIndex = 0, size = 0;
    399     GLFWvidmode* result = NULL;
    400 
    401     *count = 0;
    402 
    403     for (;;)
    404     {
    405         int i;
    406         GLFWvidmode mode;
    407         DEVMODEW dm;
    408 
    409         ZeroMemory(&dm, sizeof(dm));
    410         dm.dmSize = sizeof(dm);
    411 
    412         if (!EnumDisplaySettingsW(monitor->win32.adapterName, modeIndex, &dm))
    413             break;
    414 
    415         modeIndex++;
    416 
    417         // Skip modes with less than 15 BPP
    418         if (dm.dmBitsPerPel < 15)
    419             continue;
    420 
    421         mode.width  = dm.dmPelsWidth;
    422         mode.height = dm.dmPelsHeight;
    423         mode.refreshRate = dm.dmDisplayFrequency;
    424         _glfwSplitBPP(dm.dmBitsPerPel,
    425                       &mode.redBits,
    426                       &mode.greenBits,
    427                       &mode.blueBits);
    428 
    429         for (i = 0;  i < *count;  i++)
    430         {
    431             if (_glfwCompareVideoModes(result + i, &mode) == 0)
    432                 break;
    433         }
    434 
    435         // Skip duplicate modes
    436         if (i < *count)
    437             continue;
    438 
    439         if (monitor->win32.modesPruned)
    440         {
    441             // Skip modes not supported by the connected displays
    442             if (ChangeDisplaySettingsExW(monitor->win32.adapterName,
    443                                          &dm,
    444                                          NULL,
    445                                          CDS_TEST,
    446                                          NULL) != DISP_CHANGE_SUCCESSFUL)
    447             {
    448                 continue;
    449             }
    450         }
    451 
    452         if (*count == size)
    453         {
    454             size += 128;
    455             result = (GLFWvidmode*) _glfw_realloc(result, size * sizeof(GLFWvidmode));
    456         }
    457 
    458         (*count)++;
    459         result[*count - 1] = mode;
    460     }
    461 
    462     if (!*count)
    463     {
    464         // HACK: Report the current mode if no valid modes were found
    465         result = _glfw_calloc(1, sizeof(GLFWvidmode));
    466         _glfwGetVideoModeWin32(monitor, result);
    467         *count = 1;
    468     }
    469 
    470     return result;
    471 }
    472 
    473 GLFWbool _glfwGetVideoModeWin32(_GLFWmonitor* monitor, GLFWvidmode* mode)
    474 {
    475     DEVMODEW dm;
    476     ZeroMemory(&dm, sizeof(dm));
    477     dm.dmSize = sizeof(dm);
    478 
    479     if (!EnumDisplaySettingsW(monitor->win32.adapterName, ENUM_CURRENT_SETTINGS, &dm))
    480     {
    481         _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to query display settings");
    482         return GLFW_FALSE;
    483     }
    484 
    485     mode->width  = dm.dmPelsWidth;
    486     mode->height = dm.dmPelsHeight;
    487     mode->refreshRate = dm.dmDisplayFrequency;
    488     _glfwSplitBPP(dm.dmBitsPerPel,
    489                   &mode->redBits,
    490                   &mode->greenBits,
    491                   &mode->blueBits);
    492 
    493     return GLFW_TRUE;
    494 }
    495 
    496 GLFWbool _glfwGetGammaRampWin32(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
    497 {
    498     HDC dc;
    499     WORD values[3][256];
    500 
    501     dc = CreateDCW(L"DISPLAY", monitor->win32.adapterName, NULL, NULL);
    502     GetDeviceGammaRamp(dc, values);
    503     DeleteDC(dc);
    504 
    505     _glfwAllocGammaArrays(ramp, 256);
    506 
    507     memcpy(ramp->red,   values[0], sizeof(values[0]));
    508     memcpy(ramp->green, values[1], sizeof(values[1]));
    509     memcpy(ramp->blue,  values[2], sizeof(values[2]));
    510 
    511     return GLFW_TRUE;
    512 }
    513 
    514 void _glfwSetGammaRampWin32(_GLFWmonitor* monitor, const GLFWgammaramp* ramp)
    515 {
    516     HDC dc;
    517     WORD values[3][256];
    518 
    519     if (ramp->size != 256)
    520     {
    521         _glfwInputError(GLFW_PLATFORM_ERROR,
    522                         "Win32: Gamma ramp size must be 256");
    523         return;
    524     }
    525 
    526     memcpy(values[0], ramp->red,   sizeof(values[0]));
    527     memcpy(values[1], ramp->green, sizeof(values[1]));
    528     memcpy(values[2], ramp->blue,  sizeof(values[2]));
    529 
    530     dc = CreateDCW(L"DISPLAY", monitor->win32.adapterName, NULL, NULL);
    531     SetDeviceGammaRamp(dc, values);
    532     DeleteDC(dc);
    533 }
    534 
    535 
    536 //////////////////////////////////////////////////////////////////////////
    537 //////                        GLFW native API                       //////
    538 //////////////////////////////////////////////////////////////////////////
    539 
    540 GLFWAPI const char* glfwGetWin32Adapter(GLFWmonitor* handle)
    541 {
    542     _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
    543     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
    544 
    545     if (_glfw.platform.platformID != GLFW_PLATFORM_WIN32)
    546     {
    547         _glfwInputError(GLFW_PLATFORM_UNAVAILABLE, "Win32: Platform not initialized");
    548         return NULL;
    549     }
    550 
    551     return monitor->win32.publicAdapterName;
    552 }
    553 
    554 GLFWAPI const char* glfwGetWin32Monitor(GLFWmonitor* handle)
    555 {
    556     _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
    557     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
    558 
    559     if (_glfw.platform.platformID != GLFW_PLATFORM_WIN32)
    560     {
    561         _glfwInputError(GLFW_PLATFORM_UNAVAILABLE, "Win32: Platform not initialized");
    562         return NULL;
    563     }
    564 
    565     return monitor->win32.publicDisplayName;
    566 }
    567 
    568 #endif // _GLFW_WIN32
    569