github.com/Konstantin8105/c4go@v0.0.0-20240505174241-768bb1c65a51/tests/raylib/external/glfw/src/win32_monitor.c (about)

     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  // Please use C89 style variable declarations in this file because VS 2010
    28  //========================================================================
    29  
    30  #include "internal.h"
    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  void _glfwGetVideoModeWin32(_GLFWmonitor* monitor, GLFWvidmode* mode)
   474  {
   475      DEVMODEW dm;
   476      ZeroMemory(&dm, sizeof(dm));
   477      dm.dmSize = sizeof(dm);
   478  
   479      EnumDisplaySettingsW(monitor->win32.adapterName, ENUM_CURRENT_SETTINGS, &dm);
   480  
   481      mode->width  = dm.dmPelsWidth;
   482      mode->height = dm.dmPelsHeight;
   483      mode->refreshRate = dm.dmDisplayFrequency;
   484      _glfwSplitBPP(dm.dmBitsPerPel,
   485                    &mode->redBits,
   486                    &mode->greenBits,
   487                    &mode->blueBits);
   488  }
   489  
   490  GLFWbool _glfwGetGammaRampWin32(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
   491  {
   492      HDC dc;
   493      WORD values[3][256];
   494  
   495      dc = CreateDCW(L"DISPLAY", monitor->win32.adapterName, NULL, NULL);
   496      GetDeviceGammaRamp(dc, values);
   497      DeleteDC(dc);
   498  
   499      _glfwAllocGammaArrays(ramp, 256);
   500  
   501      memcpy(ramp->red,   values[0], sizeof(values[0]));
   502      memcpy(ramp->green, values[1], sizeof(values[1]));
   503      memcpy(ramp->blue,  values[2], sizeof(values[2]));
   504  
   505      return GLFW_TRUE;
   506  }
   507  
   508  void _glfwSetGammaRampWin32(_GLFWmonitor* monitor, const GLFWgammaramp* ramp)
   509  {
   510      HDC dc;
   511      WORD values[3][256];
   512  
   513      if (ramp->size != 256)
   514      {
   515          _glfwInputError(GLFW_PLATFORM_ERROR,
   516                          "Win32: Gamma ramp size must be 256");
   517          return;
   518      }
   519  
   520      memcpy(values[0], ramp->red,   sizeof(values[0]));
   521      memcpy(values[1], ramp->green, sizeof(values[1]));
   522      memcpy(values[2], ramp->blue,  sizeof(values[2]));
   523  
   524      dc = CreateDCW(L"DISPLAY", monitor->win32.adapterName, NULL, NULL);
   525      SetDeviceGammaRamp(dc, values);
   526      DeleteDC(dc);
   527  }
   528  
   529  
   530  //////////////////////////////////////////////////////////////////////////
   531  //////                        GLFW native API                       //////
   532  //////////////////////////////////////////////////////////////////////////
   533  
   534  GLFWAPI const char* glfwGetWin32Adapter(GLFWmonitor* handle)
   535  {
   536      _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
   537      _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
   538      return monitor->win32.publicAdapterName;
   539  }
   540  
   541  GLFWAPI const char* glfwGetWin32Monitor(GLFWmonitor* handle)
   542  {
   543      _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
   544      _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
   545      return monitor->win32.publicDisplayName;
   546  }
   547