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

     1  //========================================================================
     2  // GLFW 3.4 X11 - 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  // It is fine to use C99 in this file because it will not be built with VS
    28  //========================================================================
    29  
    30  #include "internal.h"
    31  
    32  #include <limits.h>
    33  #include <stdlib.h>
    34  #include <string.h>
    35  #include <math.h>
    36  
    37  
    38  // Check whether the display mode should be included in enumeration
    39  //
    40  static GLFWbool modeIsGood(const XRRModeInfo* mi)
    41  {
    42      return (mi->modeFlags & RR_Interlace) == 0;
    43  }
    44  
    45  // Calculates the refresh rate, in Hz, from the specified RandR mode info
    46  //
    47  static int calculateRefreshRate(const XRRModeInfo* mi)
    48  {
    49      if (mi->hTotal && mi->vTotal)
    50          return (int) round((double) mi->dotClock / ((double) mi->hTotal * (double) mi->vTotal));
    51      else
    52          return 0;
    53  }
    54  
    55  // Returns the mode info for a RandR mode XID
    56  //
    57  static const XRRModeInfo* getModeInfo(const XRRScreenResources* sr, RRMode id)
    58  {
    59      for (int i = 0;  i < sr->nmode;  i++)
    60      {
    61          if (sr->modes[i].id == id)
    62              return sr->modes + i;
    63      }
    64  
    65      return NULL;
    66  }
    67  
    68  // Convert RandR mode info to GLFW video mode
    69  //
    70  static GLFWvidmode vidmodeFromModeInfo(const XRRModeInfo* mi,
    71                                         const XRRCrtcInfo* ci)
    72  {
    73      GLFWvidmode mode;
    74  
    75      if (ci->rotation == RR_Rotate_90 || ci->rotation == RR_Rotate_270)
    76      {
    77          mode.width  = mi->height;
    78          mode.height = mi->width;
    79      }
    80      else
    81      {
    82          mode.width  = mi->width;
    83          mode.height = mi->height;
    84      }
    85  
    86      mode.refreshRate = calculateRefreshRate(mi);
    87  
    88      _glfwSplitBPP(DefaultDepth(_glfw.x11.display, _glfw.x11.screen),
    89                    &mode.redBits, &mode.greenBits, &mode.blueBits);
    90  
    91      return mode;
    92  }
    93  
    94  
    95  //////////////////////////////////////////////////////////////////////////
    96  //////                       GLFW internal API                      //////
    97  //////////////////////////////////////////////////////////////////////////
    98  
    99  // Poll for changes in the set of connected monitors
   100  //
   101  void _glfwPollMonitorsX11(void)
   102  {
   103      if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
   104      {
   105          int disconnectedCount, screenCount = 0;
   106          _GLFWmonitor** disconnected = NULL;
   107          XineramaScreenInfo* screens = NULL;
   108          XRRScreenResources* sr = XRRGetScreenResourcesCurrent(_glfw.x11.display,
   109                                                                _glfw.x11.root);
   110          RROutput primary = XRRGetOutputPrimary(_glfw.x11.display,
   111                                                 _glfw.x11.root);
   112  
   113          if (_glfw.x11.xinerama.available)
   114              screens = XineramaQueryScreens(_glfw.x11.display, &screenCount);
   115  
   116          disconnectedCount = _glfw.monitorCount;
   117          if (disconnectedCount)
   118          {
   119              disconnected = _glfw_calloc(_glfw.monitorCount, sizeof(_GLFWmonitor*));
   120              memcpy(disconnected,
   121                     _glfw.monitors,
   122                     _glfw.monitorCount * sizeof(_GLFWmonitor*));
   123          }
   124  
   125          for (int i = 0;  i < sr->noutput;  i++)
   126          {
   127              int j, type, widthMM, heightMM;
   128  
   129              XRROutputInfo* oi = XRRGetOutputInfo(_glfw.x11.display, sr, sr->outputs[i]);
   130              if (oi->connection != RR_Connected || oi->crtc == None)
   131              {
   132                  XRRFreeOutputInfo(oi);
   133                  continue;
   134              }
   135  
   136              for (j = 0;  j < disconnectedCount;  j++)
   137              {
   138                  if (disconnected[j] &&
   139                      disconnected[j]->x11.output == sr->outputs[i])
   140                  {
   141                      disconnected[j] = NULL;
   142                      break;
   143                  }
   144              }
   145  
   146              if (j < disconnectedCount)
   147              {
   148                  XRRFreeOutputInfo(oi);
   149                  continue;
   150              }
   151  
   152              XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, oi->crtc);
   153              if (ci->rotation == RR_Rotate_90 || ci->rotation == RR_Rotate_270)
   154              {
   155                  widthMM  = oi->mm_height;
   156                  heightMM = oi->mm_width;
   157              }
   158              else
   159              {
   160                  widthMM  = oi->mm_width;
   161                  heightMM = oi->mm_height;
   162              }
   163  
   164              if (widthMM <= 0 || heightMM <= 0)
   165              {
   166                  // HACK: If RandR does not provide a physical size, assume the
   167                  //       X11 default 96 DPI and calculate from the CRTC viewport
   168                  // NOTE: These members are affected by rotation, unlike the mode
   169                  //       info and output info members
   170                  widthMM  = (int) (ci->width * 25.4f / 96.f);
   171                  heightMM = (int) (ci->height * 25.4f / 96.f);
   172              }
   173  
   174              _GLFWmonitor* monitor = _glfwAllocMonitor(oi->name, widthMM, heightMM);
   175              monitor->x11.output = sr->outputs[i];
   176              monitor->x11.crtc   = oi->crtc;
   177  
   178              for (j = 0;  j < screenCount;  j++)
   179              {
   180                  if (screens[j].x_org == ci->x &&
   181                      screens[j].y_org == ci->y &&
   182                      screens[j].width == ci->width &&
   183                      screens[j].height == ci->height)
   184                  {
   185                      monitor->x11.index = j;
   186                      break;
   187                  }
   188              }
   189  
   190              if (monitor->x11.output == primary)
   191                  type = _GLFW_INSERT_FIRST;
   192              else
   193                  type = _GLFW_INSERT_LAST;
   194  
   195              _glfwInputMonitor(monitor, GLFW_CONNECTED, type);
   196  
   197              XRRFreeOutputInfo(oi);
   198              XRRFreeCrtcInfo(ci);
   199          }
   200  
   201          XRRFreeScreenResources(sr);
   202  
   203          if (screens)
   204              XFree(screens);
   205  
   206          for (int i = 0;  i < disconnectedCount;  i++)
   207          {
   208              if (disconnected[i])
   209                  _glfwInputMonitor(disconnected[i], GLFW_DISCONNECTED, 0);
   210          }
   211  
   212          _glfw_free(disconnected);
   213      }
   214      else
   215      {
   216          const int widthMM = DisplayWidthMM(_glfw.x11.display, _glfw.x11.screen);
   217          const int heightMM = DisplayHeightMM(_glfw.x11.display, _glfw.x11.screen);
   218  
   219          _glfwInputMonitor(_glfwAllocMonitor("Display", widthMM, heightMM),
   220                            GLFW_CONNECTED,
   221                            _GLFW_INSERT_FIRST);
   222      }
   223  }
   224  
   225  // Set the current video mode for the specified monitor
   226  //
   227  void _glfwSetVideoModeX11(_GLFWmonitor* monitor, const GLFWvidmode* desired)
   228  {
   229      if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
   230      {
   231          GLFWvidmode current;
   232          RRMode native = None;
   233  
   234          const GLFWvidmode* best = _glfwChooseVideoMode(monitor, desired);
   235          _glfwGetVideoModeX11(monitor, &current);
   236          if (_glfwCompareVideoModes(&current, best) == 0)
   237              return;
   238  
   239          XRRScreenResources* sr =
   240              XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
   241          XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
   242          XRROutputInfo* oi = XRRGetOutputInfo(_glfw.x11.display, sr, monitor->x11.output);
   243  
   244          for (int i = 0;  i < oi->nmode;  i++)
   245          {
   246              const XRRModeInfo* mi = getModeInfo(sr, oi->modes[i]);
   247              if (!modeIsGood(mi))
   248                  continue;
   249  
   250              const GLFWvidmode mode = vidmodeFromModeInfo(mi, ci);
   251              if (_glfwCompareVideoModes(best, &mode) == 0)
   252              {
   253                  native = mi->id;
   254                  break;
   255              }
   256          }
   257  
   258          if (native)
   259          {
   260              if (monitor->x11.oldMode == None)
   261                  monitor->x11.oldMode = ci->mode;
   262  
   263              XRRSetCrtcConfig(_glfw.x11.display,
   264                               sr, monitor->x11.crtc,
   265                               CurrentTime,
   266                               ci->x, ci->y,
   267                               native,
   268                               ci->rotation,
   269                               ci->outputs,
   270                               ci->noutput);
   271          }
   272  
   273          XRRFreeOutputInfo(oi);
   274          XRRFreeCrtcInfo(ci);
   275          XRRFreeScreenResources(sr);
   276      }
   277  }
   278  
   279  // Restore the saved (original) video mode for the specified monitor
   280  //
   281  void _glfwRestoreVideoModeX11(_GLFWmonitor* monitor)
   282  {
   283      if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
   284      {
   285          if (monitor->x11.oldMode == None)
   286              return;
   287  
   288          XRRScreenResources* sr =
   289              XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
   290          XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
   291  
   292          XRRSetCrtcConfig(_glfw.x11.display,
   293                           sr, monitor->x11.crtc,
   294                           CurrentTime,
   295                           ci->x, ci->y,
   296                           monitor->x11.oldMode,
   297                           ci->rotation,
   298                           ci->outputs,
   299                           ci->noutput);
   300  
   301          XRRFreeCrtcInfo(ci);
   302          XRRFreeScreenResources(sr);
   303  
   304          monitor->x11.oldMode = None;
   305      }
   306  }
   307  
   308  
   309  //////////////////////////////////////////////////////////////////////////
   310  //////                       GLFW platform API                      //////
   311  //////////////////////////////////////////////////////////////////////////
   312  
   313  void _glfwFreeMonitorX11(_GLFWmonitor* monitor)
   314  {
   315  }
   316  
   317  void _glfwGetMonitorPosX11(_GLFWmonitor* monitor, int* xpos, int* ypos)
   318  {
   319      if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
   320      {
   321          XRRScreenResources* sr =
   322              XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
   323          XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
   324  
   325          if (ci)
   326          {
   327              if (xpos)
   328                  *xpos = ci->x;
   329              if (ypos)
   330                  *ypos = ci->y;
   331  
   332              XRRFreeCrtcInfo(ci);
   333          }
   334  
   335          XRRFreeScreenResources(sr);
   336      }
   337  }
   338  
   339  void _glfwGetMonitorContentScaleX11(_GLFWmonitor* monitor,
   340                                      float* xscale, float* yscale)
   341  {
   342      if (xscale)
   343          *xscale = _glfw.x11.contentScaleX;
   344      if (yscale)
   345          *yscale = _glfw.x11.contentScaleY;
   346  }
   347  
   348  void _glfwGetMonitorWorkareaX11(_GLFWmonitor* monitor,
   349                                  int* xpos, int* ypos,
   350                                  int* width, int* height)
   351  {
   352      int areaX = 0, areaY = 0, areaWidth = 0, areaHeight = 0;
   353  
   354      if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
   355      {
   356          XRRScreenResources* sr =
   357              XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
   358          XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
   359  
   360          areaX = ci->x;
   361          areaY = ci->y;
   362  
   363          const XRRModeInfo* mi = getModeInfo(sr, ci->mode);
   364  
   365          if (ci->rotation == RR_Rotate_90 || ci->rotation == RR_Rotate_270)
   366          {
   367              areaWidth  = mi->height;
   368              areaHeight = mi->width;
   369          }
   370          else
   371          {
   372              areaWidth  = mi->width;
   373              areaHeight = mi->height;
   374          }
   375  
   376          XRRFreeCrtcInfo(ci);
   377          XRRFreeScreenResources(sr);
   378      }
   379      else
   380      {
   381          areaWidth  = DisplayWidth(_glfw.x11.display, _glfw.x11.screen);
   382          areaHeight = DisplayHeight(_glfw.x11.display, _glfw.x11.screen);
   383      }
   384  
   385      if (_glfw.x11.NET_WORKAREA && _glfw.x11.NET_CURRENT_DESKTOP)
   386      {
   387          Atom* extents = NULL;
   388          Atom* desktop = NULL;
   389          const unsigned long extentCount =
   390              _glfwGetWindowPropertyX11(_glfw.x11.root,
   391                                        _glfw.x11.NET_WORKAREA,
   392                                        XA_CARDINAL,
   393                                        (unsigned char**) &extents);
   394  
   395          if (_glfwGetWindowPropertyX11(_glfw.x11.root,
   396                                        _glfw.x11.NET_CURRENT_DESKTOP,
   397                                        XA_CARDINAL,
   398                                        (unsigned char**) &desktop) > 0)
   399          {
   400              if (extentCount >= 4 && *desktop < extentCount / 4)
   401              {
   402                  const int globalX = extents[*desktop * 4 + 0];
   403                  const int globalY = extents[*desktop * 4 + 1];
   404                  const int globalWidth  = extents[*desktop * 4 + 2];
   405                  const int globalHeight = extents[*desktop * 4 + 3];
   406  
   407                  if (areaX < globalX)
   408                  {
   409                      areaWidth -= globalX - areaX;
   410                      areaX = globalX;
   411                  }
   412  
   413                  if (areaY < globalY)
   414                  {
   415                      areaHeight -= globalY - areaY;
   416                      areaY = globalY;
   417                  }
   418  
   419                  if (areaX + areaWidth > globalX + globalWidth)
   420                      areaWidth = globalX - areaX + globalWidth;
   421                  if (areaY + areaHeight > globalY + globalHeight)
   422                      areaHeight = globalY - areaY + globalHeight;
   423              }
   424          }
   425  
   426          if (extents)
   427              XFree(extents);
   428          if (desktop)
   429              XFree(desktop);
   430      }
   431  
   432      if (xpos)
   433          *xpos = areaX;
   434      if (ypos)
   435          *ypos = areaY;
   436      if (width)
   437          *width = areaWidth;
   438      if (height)
   439          *height = areaHeight;
   440  }
   441  
   442  GLFWvidmode* _glfwGetVideoModesX11(_GLFWmonitor* monitor, int* count)
   443  {
   444      GLFWvidmode* result;
   445  
   446      *count = 0;
   447  
   448      if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
   449      {
   450          XRRScreenResources* sr =
   451              XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
   452          XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
   453          XRROutputInfo* oi = XRRGetOutputInfo(_glfw.x11.display, sr, monitor->x11.output);
   454  
   455          result = _glfw_calloc(oi->nmode, sizeof(GLFWvidmode));
   456  
   457          for (int i = 0;  i < oi->nmode;  i++)
   458          {
   459              const XRRModeInfo* mi = getModeInfo(sr, oi->modes[i]);
   460              if (!modeIsGood(mi))
   461                  continue;
   462  
   463              const GLFWvidmode mode = vidmodeFromModeInfo(mi, ci);
   464              int j;
   465  
   466              for (j = 0;  j < *count;  j++)
   467              {
   468                  if (_glfwCompareVideoModes(result + j, &mode) == 0)
   469                      break;
   470              }
   471  
   472              // Skip duplicate modes
   473              if (j < *count)
   474                  continue;
   475  
   476              (*count)++;
   477              result[*count - 1] = mode;
   478          }
   479  
   480          XRRFreeOutputInfo(oi);
   481          XRRFreeCrtcInfo(ci);
   482          XRRFreeScreenResources(sr);
   483      }
   484      else
   485      {
   486          *count = 1;
   487          result = _glfw_calloc(1, sizeof(GLFWvidmode));
   488          _glfwGetVideoModeX11(monitor, result);
   489      }
   490  
   491      return result;
   492  }
   493  
   494  void _glfwGetVideoModeX11(_GLFWmonitor* monitor, GLFWvidmode* mode)
   495  {
   496      if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
   497      {
   498          XRRScreenResources* sr =
   499              XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
   500          XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
   501  
   502          if (ci)
   503          {
   504              const XRRModeInfo* mi = getModeInfo(sr, ci->mode);
   505              if (mi)  // mi can be NULL if the monitor has been disconnected
   506                  *mode = vidmodeFromModeInfo(mi, ci);
   507  
   508              XRRFreeCrtcInfo(ci);
   509          }
   510  
   511          XRRFreeScreenResources(sr);
   512      }
   513      else
   514      {
   515          mode->width = DisplayWidth(_glfw.x11.display, _glfw.x11.screen);
   516          mode->height = DisplayHeight(_glfw.x11.display, _glfw.x11.screen);
   517          mode->refreshRate = 0;
   518  
   519          _glfwSplitBPP(DefaultDepth(_glfw.x11.display, _glfw.x11.screen),
   520                        &mode->redBits, &mode->greenBits, &mode->blueBits);
   521      }
   522  }
   523  
   524  GLFWbool _glfwGetGammaRampX11(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
   525  {
   526      if (_glfw.x11.randr.available && !_glfw.x11.randr.gammaBroken)
   527      {
   528          const size_t size = XRRGetCrtcGammaSize(_glfw.x11.display,
   529                                                  monitor->x11.crtc);
   530          XRRCrtcGamma* gamma = XRRGetCrtcGamma(_glfw.x11.display,
   531                                                monitor->x11.crtc);
   532  
   533          _glfwAllocGammaArrays(ramp, size);
   534  
   535          memcpy(ramp->red,   gamma->red,   size * sizeof(unsigned short));
   536          memcpy(ramp->green, gamma->green, size * sizeof(unsigned short));
   537          memcpy(ramp->blue,  gamma->blue,  size * sizeof(unsigned short));
   538  
   539          XRRFreeGamma(gamma);
   540          return GLFW_TRUE;
   541      }
   542      else if (_glfw.x11.vidmode.available)
   543      {
   544          int size;
   545          XF86VidModeGetGammaRampSize(_glfw.x11.display, _glfw.x11.screen, &size);
   546  
   547          _glfwAllocGammaArrays(ramp, size);
   548  
   549          XF86VidModeGetGammaRamp(_glfw.x11.display,
   550                                  _glfw.x11.screen,
   551                                  ramp->size, ramp->red, ramp->green, ramp->blue);
   552          return GLFW_TRUE;
   553      }
   554      else
   555      {
   556          _glfwInputError(GLFW_PLATFORM_ERROR,
   557                          "X11: Gamma ramp access not supported by server");
   558          return GLFW_FALSE;
   559      }
   560  }
   561  
   562  void _glfwSetGammaRampX11(_GLFWmonitor* monitor, const GLFWgammaramp* ramp)
   563  {
   564      if (_glfw.x11.randr.available && !_glfw.x11.randr.gammaBroken)
   565      {
   566          if (XRRGetCrtcGammaSize(_glfw.x11.display, monitor->x11.crtc) != ramp->size)
   567          {
   568              _glfwInputError(GLFW_PLATFORM_ERROR,
   569                              "X11: Gamma ramp size must match current ramp size");
   570              return;
   571          }
   572  
   573          XRRCrtcGamma* gamma = XRRAllocGamma(ramp->size);
   574  
   575          memcpy(gamma->red,   ramp->red,   ramp->size * sizeof(unsigned short));
   576          memcpy(gamma->green, ramp->green, ramp->size * sizeof(unsigned short));
   577          memcpy(gamma->blue,  ramp->blue,  ramp->size * sizeof(unsigned short));
   578  
   579          XRRSetCrtcGamma(_glfw.x11.display, monitor->x11.crtc, gamma);
   580          XRRFreeGamma(gamma);
   581      }
   582      else if (_glfw.x11.vidmode.available)
   583      {
   584          XF86VidModeSetGammaRamp(_glfw.x11.display,
   585                                  _glfw.x11.screen,
   586                                  ramp->size,
   587                                  (unsigned short*) ramp->red,
   588                                  (unsigned short*) ramp->green,
   589                                  (unsigned short*) ramp->blue);
   590      }
   591      else
   592      {
   593          _glfwInputError(GLFW_PLATFORM_ERROR,
   594                          "X11: Gamma ramp access not supported by server");
   595      }
   596  }
   597  
   598  
   599  //////////////////////////////////////////////////////////////////////////
   600  //////                        GLFW native API                       //////
   601  //////////////////////////////////////////////////////////////////////////
   602  
   603  GLFWAPI RRCrtc glfwGetX11Adapter(GLFWmonitor* handle)
   604  {
   605      _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
   606      _GLFW_REQUIRE_INIT_OR_RETURN(None);
   607      return monitor->x11.crtc;
   608  }
   609  
   610  GLFWAPI RROutput glfwGetX11Monitor(GLFWmonitor* handle)
   611  {
   612      _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
   613      _GLFW_REQUIRE_INIT_OR_RETURN(None);
   614      return monitor->x11.output;
   615  }
   616