medfall

A super great game engine
Log | Files | Refs

x11_monitor.cc (15609B)


      1 //========================================================================
      2 // GLFW 3.3 X11 - www.glfw.org
      3 //------------------------------------------------------------------------
      4 // Copyright (c) 2002-2006 Marcus Geelnard
      5 // Copyright (c) 2006-2016 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 #include <limits.h>
     31 #include <stdlib.h>
     32 #include <string.h>
     33 
     34 
     35 // Check whether the display mode should be included in enumeration
     36 //
     37 static GLFWbool modeIsGood(const XRRModeInfo* mi)
     38 {
     39     return (mi->modeFlags & RR_Interlace) == 0;
     40 }
     41 
     42 // Calculates the refresh rate, in Hz, from the specified RandR mode info
     43 //
     44 static int calculateRefreshRate(const XRRModeInfo* mi)
     45 {
     46     if (mi->hTotal && mi->vTotal)
     47         return (int) ((double) mi->dotClock / ((double) mi->hTotal * (double) mi->vTotal));
     48     else
     49         return 0;
     50 }
     51 
     52 // Returns the mode info for a RandR mode XID
     53 //
     54 static const XRRModeInfo* getModeInfo(const XRRScreenResources* sr, RRMode id)
     55 {
     56     int i;
     57 
     58     for (i = 0;  i < sr->nmode;  i++)
     59     {
     60         if (sr->modes[i].id == id)
     61             return sr->modes + i;
     62     }
     63 
     64     return NULL;
     65 }
     66 
     67 // Convert RandR mode info to GLFW video mode
     68 //
     69 static GLFWvidmode vidmodeFromModeInfo(const XRRModeInfo* mi,
     70                                        const XRRCrtcInfo* ci)
     71 {
     72     GLFWvidmode mode;
     73 
     74     if (ci->rotation == RR_Rotate_90 || ci->rotation == RR_Rotate_270)
     75     {
     76         mode.width  = mi->height;
     77         mode.height = mi->width;
     78     }
     79     else
     80     {
     81         mode.width  = mi->width;
     82         mode.height = mi->height;
     83     }
     84 
     85     mode.refreshRate = calculateRefreshRate(mi);
     86 
     87     _glfwSplitBPP(DefaultDepth(_glfw.x11.display, _glfw.x11.screen),
     88                   &mode.redBits, &mode.greenBits, &mode.blueBits);
     89 
     90     return mode;
     91 }
     92 
     93 
     94 //////////////////////////////////////////////////////////////////////////
     95 //////                       GLFW internal API                      //////
     96 //////////////////////////////////////////////////////////////////////////
     97 
     98 // Poll for changes in the set of connected monitors
     99 //
    100 void _glfwPollMonitorsX11(void)
    101 {
    102     if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
    103     {
    104         int i, j, disconnectedCount, screenCount = 0;
    105         _GLFWmonitor** disconnected = NULL;
    106         XineramaScreenInfo* screens = NULL;
    107         XRRScreenResources* sr = XRRGetScreenResourcesCurrent(_glfw.x11.display,
    108                                                               _glfw.x11.root);
    109         RROutput primary = XRRGetOutputPrimary(_glfw.x11.display,
    110                                                _glfw.x11.root);
    111 
    112         if (_glfw.x11.xinerama.available)
    113             screens = XineramaQueryScreens(_glfw.x11.display, &screenCount);
    114 
    115         disconnectedCount = _glfw.monitorCount;
    116         if (disconnectedCount)
    117         {
    118             disconnected = calloc(_glfw.monitorCount, sizeof(_GLFWmonitor*));
    119             memcpy(disconnected,
    120                    _glfw.monitors,
    121                    _glfw.monitorCount * sizeof(_GLFWmonitor*));
    122         }
    123 
    124         for (i = 0;  i < sr->noutput;  i++)
    125         {
    126             int type, widthMM, heightMM;
    127             XRROutputInfo* oi;
    128             XRRCrtcInfo* ci;
    129             _GLFWmonitor* monitor;
    130 
    131             oi = XRRGetOutputInfo(_glfw.x11.display, sr, sr->outputs[i]);
    132             if (oi->connection != RR_Connected || oi->crtc == None)
    133             {
    134                 XRRFreeOutputInfo(oi);
    135                 continue;
    136             }
    137 
    138             for (j = 0;  j < disconnectedCount;  j++)
    139             {
    140                 if (disconnected[j] &&
    141                     disconnected[j]->x11.output == sr->outputs[i])
    142                 {
    143                     disconnected[j] = NULL;
    144                     break;
    145                 }
    146             }
    147 
    148             if (j < disconnectedCount)
    149             {
    150                 XRRFreeOutputInfo(oi);
    151                 continue;
    152             }
    153 
    154             ci = XRRGetCrtcInfo(_glfw.x11.display, sr, oi->crtc);
    155             if (ci->rotation == RR_Rotate_90 || ci->rotation == RR_Rotate_270)
    156             {
    157                 widthMM  = oi->mm_height;
    158                 heightMM = oi->mm_width;
    159             }
    160             else
    161             {
    162                 widthMM  = oi->mm_width;
    163                 heightMM = oi->mm_height;
    164             }
    165 
    166             monitor = _glfwAllocMonitor(oi->name, widthMM, heightMM);
    167             monitor->x11.output = sr->outputs[i];
    168             monitor->x11.crtc   = oi->crtc;
    169 
    170             for (j = 0;  j < screenCount;  j++)
    171             {
    172                 if (screens[j].x_org == ci->x &&
    173                     screens[j].y_org == ci->y &&
    174                     screens[j].width == ci->width &&
    175                     screens[j].height == ci->height)
    176                 {
    177                     monitor->x11.index = j;
    178                     break;
    179                 }
    180             }
    181 
    182             if (monitor->x11.output == primary)
    183                 type = _GLFW_INSERT_FIRST;
    184             else
    185                 type = _GLFW_INSERT_LAST;
    186 
    187             _glfwInputMonitor(monitor, GLFW_CONNECTED, type);
    188 
    189             XRRFreeOutputInfo(oi);
    190             XRRFreeCrtcInfo(ci);
    191         }
    192 
    193         XRRFreeScreenResources(sr);
    194 
    195         if (screens)
    196             XFree(screens);
    197 
    198         for (i = 0;  i < disconnectedCount;  i++)
    199         {
    200             if (disconnected[i])
    201                 _glfwInputMonitor(disconnected[i], GLFW_DISCONNECTED, 0);
    202         }
    203 
    204         free(disconnected);
    205     }
    206 
    207     if (!_glfw.monitorCount)
    208     {
    209         const int widthMM = DisplayWidthMM(_glfw.x11.display, _glfw.x11.screen);
    210         const int heightMM = DisplayHeightMM(_glfw.x11.display, _glfw.x11.screen);
    211 
    212         _glfwInputMonitor(_glfwAllocMonitor("Display", widthMM, heightMM),
    213                           GLFW_CONNECTED,
    214                           _GLFW_INSERT_FIRST);
    215     }
    216 }
    217 
    218 // Set the current video mode for the specified monitor
    219 //
    220 GLFWbool _glfwSetVideoModeX11(_GLFWmonitor* monitor, const GLFWvidmode* desired)
    221 {
    222     if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
    223     {
    224         XRRScreenResources* sr;
    225         XRRCrtcInfo* ci;
    226         XRROutputInfo* oi;
    227         GLFWvidmode current;
    228         const GLFWvidmode* best;
    229         RRMode native = None;
    230         int i;
    231 
    232         best = _glfwChooseVideoMode(monitor, desired);
    233         _glfwPlatformGetVideoMode(monitor, &current);
    234         if (_glfwCompareVideoModes(&current, best) == 0)
    235             return GLFW_TRUE;
    236 
    237         sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
    238         ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
    239         oi = XRRGetOutputInfo(_glfw.x11.display, sr, monitor->x11.output);
    240 
    241         for (i = 0;  i < oi->nmode;  i++)
    242         {
    243             const XRRModeInfo* mi = getModeInfo(sr, oi->modes[i]);
    244             if (!modeIsGood(mi))
    245                 continue;
    246 
    247             const GLFWvidmode mode = vidmodeFromModeInfo(mi, ci);
    248             if (_glfwCompareVideoModes(best, &mode) == 0)
    249             {
    250                 native = mi->id;
    251                 break;
    252             }
    253         }
    254 
    255         if (native)
    256         {
    257             if (monitor->x11.oldMode == None)
    258                 monitor->x11.oldMode = ci->mode;
    259 
    260             XRRSetCrtcConfig(_glfw.x11.display,
    261                              sr, monitor->x11.crtc,
    262                              CurrentTime,
    263                              ci->x, ci->y,
    264                              native,
    265                              ci->rotation,
    266                              ci->outputs,
    267                              ci->noutput);
    268         }
    269 
    270         XRRFreeOutputInfo(oi);
    271         XRRFreeCrtcInfo(ci);
    272         XRRFreeScreenResources(sr);
    273 
    274         if (!native)
    275         {
    276             _glfwInputError(GLFW_PLATFORM_ERROR,
    277                             "X11: Monitor mode list changed");
    278             return GLFW_FALSE;
    279         }
    280     }
    281 
    282     return GLFW_TRUE;
    283 }
    284 
    285 // Restore the saved (original) video mode for the specified monitor
    286 //
    287 void _glfwRestoreVideoModeX11(_GLFWmonitor* monitor)
    288 {
    289     if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
    290     {
    291         XRRScreenResources* sr;
    292         XRRCrtcInfo* ci;
    293 
    294         if (monitor->x11.oldMode == None)
    295             return;
    296 
    297         sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
    298         ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
    299 
    300         XRRSetCrtcConfig(_glfw.x11.display,
    301                          sr, monitor->x11.crtc,
    302                          CurrentTime,
    303                          ci->x, ci->y,
    304                          monitor->x11.oldMode,
    305                          ci->rotation,
    306                          ci->outputs,
    307                          ci->noutput);
    308 
    309         XRRFreeCrtcInfo(ci);
    310         XRRFreeScreenResources(sr);
    311 
    312         monitor->x11.oldMode = None;
    313     }
    314 }
    315 
    316 
    317 //////////////////////////////////////////////////////////////////////////
    318 //////                       GLFW platform API                      //////
    319 //////////////////////////////////////////////////////////////////////////
    320 
    321 void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos)
    322 {
    323     if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
    324     {
    325         XRRScreenResources* sr;
    326         XRRCrtcInfo* ci;
    327 
    328         sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
    329         ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
    330 
    331         if (xpos)
    332             *xpos = ci->x;
    333         if (ypos)
    334             *ypos = ci->y;
    335 
    336         XRRFreeCrtcInfo(ci);
    337         XRRFreeScreenResources(sr);
    338     }
    339 }
    340 
    341 GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count)
    342 {
    343     GLFWvidmode* result;
    344 
    345     *count = 0;
    346 
    347     if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
    348     {
    349         int i, j;
    350         XRRScreenResources* sr;
    351         XRRCrtcInfo* ci;
    352         XRROutputInfo* oi;
    353 
    354         sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
    355         ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
    356         oi = XRRGetOutputInfo(_glfw.x11.display, sr, monitor->x11.output);
    357 
    358         result = calloc(oi->nmode, sizeof(GLFWvidmode));
    359 
    360         for (i = 0;  i < oi->nmode;  i++)
    361         {
    362             const XRRModeInfo* mi = getModeInfo(sr, oi->modes[i]);
    363             if (!modeIsGood(mi))
    364                 continue;
    365 
    366             const GLFWvidmode mode = vidmodeFromModeInfo(mi, ci);
    367 
    368             for (j = 0;  j < *count;  j++)
    369             {
    370                 if (_glfwCompareVideoModes(result + j, &mode) == 0)
    371                     break;
    372             }
    373 
    374             // Skip duplicate modes
    375             if (j < *count)
    376                 continue;
    377 
    378             (*count)++;
    379             result[*count - 1] = mode;
    380         }
    381 
    382         XRRFreeOutputInfo(oi);
    383         XRRFreeCrtcInfo(ci);
    384         XRRFreeScreenResources(sr);
    385     }
    386     else
    387     {
    388         *count = 1;
    389         result = calloc(1, sizeof(GLFWvidmode));
    390         _glfwPlatformGetVideoMode(monitor, result);
    391     }
    392 
    393     return result;
    394 }
    395 
    396 void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode)
    397 {
    398     if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
    399     {
    400         XRRScreenResources* sr;
    401         XRRCrtcInfo* ci;
    402 
    403         sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
    404         ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
    405 
    406         *mode = vidmodeFromModeInfo(getModeInfo(sr, ci->mode), ci);
    407 
    408         XRRFreeCrtcInfo(ci);
    409         XRRFreeScreenResources(sr);
    410     }
    411     else
    412     {
    413         mode->width = DisplayWidth(_glfw.x11.display, _glfw.x11.screen);
    414         mode->height = DisplayHeight(_glfw.x11.display, _glfw.x11.screen);
    415         mode->refreshRate = 0;
    416 
    417         _glfwSplitBPP(DefaultDepth(_glfw.x11.display, _glfw.x11.screen),
    418                       &mode->redBits, &mode->greenBits, &mode->blueBits);
    419     }
    420 }
    421 
    422 void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
    423 {
    424     if (_glfw.x11.randr.available && !_glfw.x11.randr.gammaBroken)
    425     {
    426         const size_t size = XRRGetCrtcGammaSize(_glfw.x11.display,
    427                                                 monitor->x11.crtc);
    428         XRRCrtcGamma* gamma = XRRGetCrtcGamma(_glfw.x11.display,
    429                                               monitor->x11.crtc);
    430 
    431         _glfwAllocGammaArrays(ramp, size);
    432 
    433         memcpy(ramp->red,   gamma->red,   size * sizeof(unsigned short));
    434         memcpy(ramp->green, gamma->green, size * sizeof(unsigned short));
    435         memcpy(ramp->blue,  gamma->blue,  size * sizeof(unsigned short));
    436 
    437         XRRFreeGamma(gamma);
    438     }
    439     else if (_glfw.x11.vidmode.available)
    440     {
    441         int size;
    442         XF86VidModeGetGammaRampSize(_glfw.x11.display, _glfw.x11.screen, &size);
    443 
    444         _glfwAllocGammaArrays(ramp, size);
    445 
    446         XF86VidModeGetGammaRamp(_glfw.x11.display,
    447                                 _glfw.x11.screen,
    448                                 ramp->size, ramp->red, ramp->green, ramp->blue);
    449     }
    450 }
    451 
    452 void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp)
    453 {
    454     if (_glfw.x11.randr.available && !_glfw.x11.randr.gammaBroken)
    455     {
    456         if (XRRGetCrtcGammaSize(_glfw.x11.display, monitor->x11.crtc) != ramp->size)
    457         {
    458             _glfwInputError(GLFW_PLATFORM_ERROR,
    459                             "X11: Gamma ramp size must match current ramp size");
    460             return;
    461         }
    462 
    463         XRRCrtcGamma* gamma = XRRAllocGamma(ramp->size);
    464 
    465         memcpy(gamma->red,   ramp->red,   ramp->size * sizeof(unsigned short));
    466         memcpy(gamma->green, ramp->green, ramp->size * sizeof(unsigned short));
    467         memcpy(gamma->blue,  ramp->blue,  ramp->size * sizeof(unsigned short));
    468 
    469         XRRSetCrtcGamma(_glfw.x11.display, monitor->x11.crtc, gamma);
    470         XRRFreeGamma(gamma);
    471     }
    472     else if (_glfw.x11.vidmode.available)
    473     {
    474         XF86VidModeSetGammaRamp(_glfw.x11.display,
    475                                 _glfw.x11.screen,
    476                                 ramp->size,
    477                                 (unsigned short*) ramp->red,
    478                                 (unsigned short*) ramp->green,
    479                                 (unsigned short*) ramp->blue);
    480     }
    481 }
    482 
    483 
    484 //////////////////////////////////////////////////////////////////////////
    485 //////                        GLFW native API                       //////
    486 //////////////////////////////////////////////////////////////////////////
    487 
    488 GLFWAPI RRCrtc glfwGetX11Adapter(GLFWmonitor* handle)
    489 {
    490     _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
    491     _GLFW_REQUIRE_INIT_OR_RETURN(None);
    492     return monitor->x11.crtc;
    493 }
    494 
    495 GLFWAPI RROutput glfwGetX11Monitor(GLFWmonitor* handle)
    496 {
    497     _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
    498     _GLFW_REQUIRE_INIT_OR_RETURN(None);
    499     return monitor->x11.output;
    500 }
    501