]> git.sesse.net Git - pistorm/blobdiff - raylib_pi4_test/external/glfw/src/win32_monitor.c
[MEGA-WIP] Raylib-based RTG output
[pistorm] / raylib_pi4_test / external / glfw / src / win32_monitor.c
diff --git a/raylib_pi4_test/external/glfw/src/win32_monitor.c b/raylib_pi4_test/external/glfw/src/win32_monitor.c
new file mode 100644 (file)
index 0000000..b4c53e4
--- /dev/null
@@ -0,0 +1,537 @@
+//========================================================================
+// 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"
+
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <malloc.h>
+#include <wchar.h>
+
+
+// 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;
+    }
+
+    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);
+    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 = 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)
+            {
+                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)
+            {
+                free(disconnected);
+                return;
+            }
+
+            _glfwInputMonitor(monitor, GLFW_CONNECTED, type);
+        }
+    }
+
+    for (i = 0;  i < disconnectedCount;  i++)
+    {
+        if (disconnected[i])
+            _glfwInputMonitor(disconnected[i], GLFW_DISCONNECTED, 0);
+    }
+
+    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);
+    _glfwPlatformGetVideoMode(monitor, &current);
+    if (_glfwCompareVideoModes(&current, 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 _glfwGetMonitorContentScaleWin32(HMONITOR handle, float* xscale, float* yscale)
+{
+    UINT xdpi, ydpi;
+
+    if (IsWindows8Point1OrGreater())
+        GetDpiForMonitor(handle, MDT_EFFECTIVE_DPI, &xdpi, &ydpi);
+    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 _glfwPlatformFreeMonitor(_GLFWmonitor* monitor)
+{
+}
+
+void _glfwPlatformGetMonitorPos(_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 _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor,
+                                         float* xscale, float* yscale)
+{
+    _glfwGetMonitorContentScaleWin32(monitor->win32.handle, xscale, yscale);
+}
+
+void _glfwPlatformGetMonitorWorkarea(_GLFWmonitor* monitor,
+                                     int* xpos, int* ypos,
+                                     int* width, int* height)
+{
+    MONITORINFO mi = { sizeof(mi) };
+    GetMonitorInfo(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* _glfwPlatformGetVideoModes(_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*) realloc(result, size * sizeof(GLFWvidmode));
+        }
+
+        (*count)++;
+        result[*count - 1] = mode;
+    }
+
+    if (!*count)
+    {
+        // HACK: Report the current mode if no valid modes were found
+        result = calloc(1, sizeof(GLFWvidmode));
+        _glfwPlatformGetVideoMode(monitor, result);
+        *count = 1;
+    }
+
+    return result;
+}
+
+void _glfwPlatformGetVideoMode(_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 _glfwPlatformGetGammaRamp(_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 _glfwPlatformSetGammaRamp(_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;
+}
+