volviewer

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

x11_monitor.c (20136B)


      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 
     28 #include "internal.h"
     29 
     30 #if defined(_GLFW_X11)
     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 GLFWbool _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         const XRRModeInfo* mi = NULL;
    501 
    502         XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
    503         if (ci)
    504         {
    505             mi = getModeInfo(sr, ci->mode);
    506             if (mi)
    507                 *mode = vidmodeFromModeInfo(mi, ci);
    508 
    509             XRRFreeCrtcInfo(ci);
    510         }
    511 
    512         XRRFreeScreenResources(sr);
    513 
    514         if (!mi)
    515         {
    516             _glfwInputError(GLFW_PLATFORM_ERROR, "X11: Failed to query video mode");
    517             return GLFW_FALSE;
    518         }
    519     }
    520     else
    521     {
    522         mode->width = DisplayWidth(_glfw.x11.display, _glfw.x11.screen);
    523         mode->height = DisplayHeight(_glfw.x11.display, _glfw.x11.screen);
    524         mode->refreshRate = 0;
    525 
    526         _glfwSplitBPP(DefaultDepth(_glfw.x11.display, _glfw.x11.screen),
    527                       &mode->redBits, &mode->greenBits, &mode->blueBits);
    528     }
    529 
    530     return GLFW_TRUE;
    531 }
    532 
    533 GLFWbool _glfwGetGammaRampX11(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
    534 {
    535     if (_glfw.x11.randr.available && !_glfw.x11.randr.gammaBroken)
    536     {
    537         const size_t size = XRRGetCrtcGammaSize(_glfw.x11.display,
    538                                                 monitor->x11.crtc);
    539         XRRCrtcGamma* gamma = XRRGetCrtcGamma(_glfw.x11.display,
    540                                               monitor->x11.crtc);
    541 
    542         _glfwAllocGammaArrays(ramp, size);
    543 
    544         memcpy(ramp->red,   gamma->red,   size * sizeof(unsigned short));
    545         memcpy(ramp->green, gamma->green, size * sizeof(unsigned short));
    546         memcpy(ramp->blue,  gamma->blue,  size * sizeof(unsigned short));
    547 
    548         XRRFreeGamma(gamma);
    549         return GLFW_TRUE;
    550     }
    551     else if (_glfw.x11.vidmode.available)
    552     {
    553         int size;
    554         XF86VidModeGetGammaRampSize(_glfw.x11.display, _glfw.x11.screen, &size);
    555 
    556         _glfwAllocGammaArrays(ramp, size);
    557 
    558         XF86VidModeGetGammaRamp(_glfw.x11.display,
    559                                 _glfw.x11.screen,
    560                                 ramp->size, ramp->red, ramp->green, ramp->blue);
    561         return GLFW_TRUE;
    562     }
    563     else
    564     {
    565         _glfwInputError(GLFW_PLATFORM_ERROR,
    566                         "X11: Gamma ramp access not supported by server");
    567         return GLFW_FALSE;
    568     }
    569 }
    570 
    571 void _glfwSetGammaRampX11(_GLFWmonitor* monitor, const GLFWgammaramp* ramp)
    572 {
    573     if (_glfw.x11.randr.available && !_glfw.x11.randr.gammaBroken)
    574     {
    575         if (XRRGetCrtcGammaSize(_glfw.x11.display, monitor->x11.crtc) != ramp->size)
    576         {
    577             _glfwInputError(GLFW_PLATFORM_ERROR,
    578                             "X11: Gamma ramp size must match current ramp size");
    579             return;
    580         }
    581 
    582         XRRCrtcGamma* gamma = XRRAllocGamma(ramp->size);
    583 
    584         memcpy(gamma->red,   ramp->red,   ramp->size * sizeof(unsigned short));
    585         memcpy(gamma->green, ramp->green, ramp->size * sizeof(unsigned short));
    586         memcpy(gamma->blue,  ramp->blue,  ramp->size * sizeof(unsigned short));
    587 
    588         XRRSetCrtcGamma(_glfw.x11.display, monitor->x11.crtc, gamma);
    589         XRRFreeGamma(gamma);
    590     }
    591     else if (_glfw.x11.vidmode.available)
    592     {
    593         XF86VidModeSetGammaRamp(_glfw.x11.display,
    594                                 _glfw.x11.screen,
    595                                 ramp->size,
    596                                 (unsigned short*) ramp->red,
    597                                 (unsigned short*) ramp->green,
    598                                 (unsigned short*) ramp->blue);
    599     }
    600     else
    601     {
    602         _glfwInputError(GLFW_PLATFORM_ERROR,
    603                         "X11: Gamma ramp access not supported by server");
    604     }
    605 }
    606 
    607 
    608 //////////////////////////////////////////////////////////////////////////
    609 //////                        GLFW native API                       //////
    610 //////////////////////////////////////////////////////////////////////////
    611 
    612 GLFWAPI RRCrtc glfwGetX11Adapter(GLFWmonitor* handle)
    613 {
    614     _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
    615     _GLFW_REQUIRE_INIT_OR_RETURN(None);
    616 
    617     if (_glfw.platform.platformID != GLFW_PLATFORM_X11)
    618     {
    619         _glfwInputError(GLFW_PLATFORM_UNAVAILABLE, "X11: Platform not initialized");
    620         return None;
    621     }
    622 
    623     return monitor->x11.crtc;
    624 }
    625 
    626 GLFWAPI RROutput glfwGetX11Monitor(GLFWmonitor* handle)
    627 {
    628     _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
    629     _GLFW_REQUIRE_INIT_OR_RETURN(None);
    630 
    631     if (_glfw.platform.platformID != GLFW_PLATFORM_X11)
    632     {
    633         _glfwInputError(GLFW_PLATFORM_UNAVAILABLE, "X11: Platform not initialized");
    634         return None;
    635     }
    636 
    637     return monitor->x11.output;
    638 }
    639 
    640 #endif // _GLFW_X11
    641