]> git.sesse.net Git - pistorm/blobdiff - raylib_pi4_test/external/glfw/src/x11_monitor.c
[MEGA-WIP] Raylib-based RTG output
[pistorm] / raylib_pi4_test / external / glfw / src / x11_monitor.c
diff --git a/raylib_pi4_test/external/glfw/src/x11_monitor.c b/raylib_pi4_test/external/glfw/src/x11_monitor.c
new file mode 100644 (file)
index 0000000..8de8659
--- /dev/null
@@ -0,0 +1,614 @@
+//========================================================================
+// GLFW 3.4 X11 - 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.
+//
+//========================================================================
+// It is fine to use C99 in this file because it will not be built with VS
+//========================================================================
+
+#include "internal.h"
+
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+
+// Check whether the display mode should be included in enumeration
+//
+static GLFWbool modeIsGood(const XRRModeInfo* mi)
+{
+    return (mi->modeFlags & RR_Interlace) == 0;
+}
+
+// Calculates the refresh rate, in Hz, from the specified RandR mode info
+//
+static int calculateRefreshRate(const XRRModeInfo* mi)
+{
+    if (mi->hTotal && mi->vTotal)
+        return (int) round((double) mi->dotClock / ((double) mi->hTotal * (double) mi->vTotal));
+    else
+        return 0;
+}
+
+// Returns the mode info for a RandR mode XID
+//
+static const XRRModeInfo* getModeInfo(const XRRScreenResources* sr, RRMode id)
+{
+    for (int i = 0;  i < sr->nmode;  i++)
+    {
+        if (sr->modes[i].id == id)
+            return sr->modes + i;
+    }
+
+    return NULL;
+}
+
+// Convert RandR mode info to GLFW video mode
+//
+static GLFWvidmode vidmodeFromModeInfo(const XRRModeInfo* mi,
+                                       const XRRCrtcInfo* ci)
+{
+    GLFWvidmode mode;
+
+    if (ci->rotation == RR_Rotate_90 || ci->rotation == RR_Rotate_270)
+    {
+        mode.width  = mi->height;
+        mode.height = mi->width;
+    }
+    else
+    {
+        mode.width  = mi->width;
+        mode.height = mi->height;
+    }
+
+    mode.refreshRate = calculateRefreshRate(mi);
+
+    _glfwSplitBPP(DefaultDepth(_glfw.x11.display, _glfw.x11.screen),
+                  &mode.redBits, &mode.greenBits, &mode.blueBits);
+
+    return mode;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+//////                       GLFW internal API                      //////
+//////////////////////////////////////////////////////////////////////////
+
+// Poll for changes in the set of connected monitors
+//
+void _glfwPollMonitorsX11(void)
+{
+    if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
+    {
+        int disconnectedCount, screenCount = 0;
+        _GLFWmonitor** disconnected = NULL;
+        XineramaScreenInfo* screens = NULL;
+        XRRScreenResources* sr = XRRGetScreenResourcesCurrent(_glfw.x11.display,
+                                                              _glfw.x11.root);
+        RROutput primary = XRRGetOutputPrimary(_glfw.x11.display,
+                                               _glfw.x11.root);
+
+        if (_glfw.x11.xinerama.available)
+            screens = XineramaQueryScreens(_glfw.x11.display, &screenCount);
+
+        disconnectedCount = _glfw.monitorCount;
+        if (disconnectedCount)
+        {
+            disconnected = calloc(_glfw.monitorCount, sizeof(_GLFWmonitor*));
+            memcpy(disconnected,
+                   _glfw.monitors,
+                   _glfw.monitorCount * sizeof(_GLFWmonitor*));
+        }
+
+        for (int i = 0;  i < sr->noutput;  i++)
+        {
+            int j, type, widthMM, heightMM;
+
+            XRROutputInfo* oi = XRRGetOutputInfo(_glfw.x11.display, sr, sr->outputs[i]);
+            if (oi->connection != RR_Connected || oi->crtc == None)
+            {
+                XRRFreeOutputInfo(oi);
+                continue;
+            }
+
+            for (j = 0;  j < disconnectedCount;  j++)
+            {
+                if (disconnected[j] &&
+                    disconnected[j]->x11.output == sr->outputs[i])
+                {
+                    disconnected[j] = NULL;
+                    break;
+                }
+            }
+
+            if (j < disconnectedCount)
+            {
+                XRRFreeOutputInfo(oi);
+                continue;
+            }
+
+            XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, oi->crtc);
+            if (ci->rotation == RR_Rotate_90 || ci->rotation == RR_Rotate_270)
+            {
+                widthMM  = oi->mm_height;
+                heightMM = oi->mm_width;
+            }
+            else
+            {
+                widthMM  = oi->mm_width;
+                heightMM = oi->mm_height;
+            }
+
+            if (widthMM <= 0 || heightMM <= 0)
+            {
+                // HACK: If RandR does not provide a physical size, assume the
+                //       X11 default 96 DPI and calculate from the CRTC viewport
+                // NOTE: These members are affected by rotation, unlike the mode
+                //       info and output info members
+                widthMM  = (int) (ci->width * 25.4f / 96.f);
+                heightMM = (int) (ci->height * 25.4f / 96.f);
+            }
+
+            _GLFWmonitor* monitor = _glfwAllocMonitor(oi->name, widthMM, heightMM);
+            monitor->x11.output = sr->outputs[i];
+            monitor->x11.crtc   = oi->crtc;
+
+            for (j = 0;  j < screenCount;  j++)
+            {
+                if (screens[j].x_org == ci->x &&
+                    screens[j].y_org == ci->y &&
+                    screens[j].width == ci->width &&
+                    screens[j].height == ci->height)
+                {
+                    monitor->x11.index = j;
+                    break;
+                }
+            }
+
+            if (monitor->x11.output == primary)
+                type = _GLFW_INSERT_FIRST;
+            else
+                type = _GLFW_INSERT_LAST;
+
+            _glfwInputMonitor(monitor, GLFW_CONNECTED, type);
+
+            XRRFreeOutputInfo(oi);
+            XRRFreeCrtcInfo(ci);
+        }
+
+        XRRFreeScreenResources(sr);
+
+        if (screens)
+            XFree(screens);
+
+        for (int i = 0;  i < disconnectedCount;  i++)
+        {
+            if (disconnected[i])
+                _glfwInputMonitor(disconnected[i], GLFW_DISCONNECTED, 0);
+        }
+
+        free(disconnected);
+    }
+    else
+    {
+        const int widthMM = DisplayWidthMM(_glfw.x11.display, _glfw.x11.screen);
+        const int heightMM = DisplayHeightMM(_glfw.x11.display, _glfw.x11.screen);
+
+        _glfwInputMonitor(_glfwAllocMonitor("Display", widthMM, heightMM),
+                          GLFW_CONNECTED,
+                          _GLFW_INSERT_FIRST);
+    }
+}
+
+// Set the current video mode for the specified monitor
+//
+void _glfwSetVideoModeX11(_GLFWmonitor* monitor, const GLFWvidmode* desired)
+{
+    if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
+    {
+        GLFWvidmode current;
+        RRMode native = None;
+
+        const GLFWvidmode* best = _glfwChooseVideoMode(monitor, desired);
+        _glfwPlatformGetVideoMode(monitor, &current);
+        if (_glfwCompareVideoModes(&current, best) == 0)
+            return;
+
+        XRRScreenResources* sr =
+            XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
+        XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
+        XRROutputInfo* oi = XRRGetOutputInfo(_glfw.x11.display, sr, monitor->x11.output);
+
+        for (int i = 0;  i < oi->nmode;  i++)
+        {
+            const XRRModeInfo* mi = getModeInfo(sr, oi->modes[i]);
+            if (!modeIsGood(mi))
+                continue;
+
+            const GLFWvidmode mode = vidmodeFromModeInfo(mi, ci);
+            if (_glfwCompareVideoModes(best, &mode) == 0)
+            {
+                native = mi->id;
+                break;
+            }
+        }
+
+        if (native)
+        {
+            if (monitor->x11.oldMode == None)
+                monitor->x11.oldMode = ci->mode;
+
+            XRRSetCrtcConfig(_glfw.x11.display,
+                             sr, monitor->x11.crtc,
+                             CurrentTime,
+                             ci->x, ci->y,
+                             native,
+                             ci->rotation,
+                             ci->outputs,
+                             ci->noutput);
+        }
+
+        XRRFreeOutputInfo(oi);
+        XRRFreeCrtcInfo(ci);
+        XRRFreeScreenResources(sr);
+    }
+}
+
+// Restore the saved (original) video mode for the specified monitor
+//
+void _glfwRestoreVideoModeX11(_GLFWmonitor* monitor)
+{
+    if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
+    {
+        if (monitor->x11.oldMode == None)
+            return;
+
+        XRRScreenResources* sr =
+            XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
+        XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
+
+        XRRSetCrtcConfig(_glfw.x11.display,
+                         sr, monitor->x11.crtc,
+                         CurrentTime,
+                         ci->x, ci->y,
+                         monitor->x11.oldMode,
+                         ci->rotation,
+                         ci->outputs,
+                         ci->noutput);
+
+        XRRFreeCrtcInfo(ci);
+        XRRFreeScreenResources(sr);
+
+        monitor->x11.oldMode = None;
+    }
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+//////                       GLFW platform API                      //////
+//////////////////////////////////////////////////////////////////////////
+
+void _glfwPlatformFreeMonitor(_GLFWmonitor* monitor)
+{
+}
+
+void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos)
+{
+    if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
+    {
+        XRRScreenResources* sr =
+            XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
+        XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
+
+        if (ci)
+        {
+            if (xpos)
+                *xpos = ci->x;
+            if (ypos)
+                *ypos = ci->y;
+
+            XRRFreeCrtcInfo(ci);
+        }
+
+        XRRFreeScreenResources(sr);
+    }
+}
+
+void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor,
+                                         float* xscale, float* yscale)
+{
+    if (xscale)
+        *xscale = _glfw.x11.contentScaleX;
+    if (yscale)
+        *yscale = _glfw.x11.contentScaleY;
+}
+
+void _glfwPlatformGetMonitorWorkarea(_GLFWmonitor* monitor, int* xpos, int* ypos, int* width, int* height)
+{
+    int areaX = 0, areaY = 0, areaWidth = 0, areaHeight = 0;
+
+    if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
+    {
+        XRRScreenResources* sr =
+            XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
+        XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
+
+        areaX = ci->x;
+        areaY = ci->y;
+
+        const XRRModeInfo* mi = getModeInfo(sr, ci->mode);
+
+        if (ci->rotation == RR_Rotate_90 || ci->rotation == RR_Rotate_270)
+        {
+            areaWidth  = mi->height;
+            areaHeight = mi->width;
+        }
+        else
+        {
+            areaWidth  = mi->width;
+            areaHeight = mi->height;
+        }
+
+        XRRFreeCrtcInfo(ci);
+        XRRFreeScreenResources(sr);
+    }
+    else
+    {
+        areaWidth  = DisplayWidth(_glfw.x11.display, _glfw.x11.screen);
+        areaHeight = DisplayHeight(_glfw.x11.display, _glfw.x11.screen);
+    }
+
+    if (_glfw.x11.NET_WORKAREA && _glfw.x11.NET_CURRENT_DESKTOP)
+    {
+        Atom* extents = NULL;
+        Atom* desktop = NULL;
+        const unsigned long extentCount =
+            _glfwGetWindowPropertyX11(_glfw.x11.root,
+                                      _glfw.x11.NET_WORKAREA,
+                                      XA_CARDINAL,
+                                      (unsigned char**) &extents);
+
+        if (_glfwGetWindowPropertyX11(_glfw.x11.root,
+                                      _glfw.x11.NET_CURRENT_DESKTOP,
+                                      XA_CARDINAL,
+                                      (unsigned char**) &desktop) > 0)
+        {
+            if (extentCount >= 4 && *desktop < extentCount / 4)
+            {
+                const int globalX = extents[*desktop * 4 + 0];
+                const int globalY = extents[*desktop * 4 + 1];
+                const int globalWidth  = extents[*desktop * 4 + 2];
+                const int globalHeight = extents[*desktop * 4 + 3];
+
+                if (areaX < globalX)
+                {
+                    areaWidth -= globalX - areaX;
+                    areaX = globalX;
+                }
+
+                if (areaY < globalY)
+                {
+                    areaHeight -= globalY - areaY;
+                    areaY = globalY;
+                }
+
+                if (areaX + areaWidth > globalX + globalWidth)
+                    areaWidth = globalX - areaX + globalWidth;
+                if (areaY + areaHeight > globalY + globalHeight)
+                    areaHeight = globalY - areaY + globalHeight;
+            }
+        }
+
+        if (extents)
+            XFree(extents);
+        if (desktop)
+            XFree(desktop);
+    }
+
+    if (xpos)
+        *xpos = areaX;
+    if (ypos)
+        *ypos = areaY;
+    if (width)
+        *width = areaWidth;
+    if (height)
+        *height = areaHeight;
+}
+
+GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count)
+{
+    GLFWvidmode* result;
+
+    *count = 0;
+
+    if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
+    {
+        XRRScreenResources* sr =
+            XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
+        XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
+        XRROutputInfo* oi = XRRGetOutputInfo(_glfw.x11.display, sr, monitor->x11.output);
+
+        result = calloc(oi->nmode, sizeof(GLFWvidmode));
+
+        for (int i = 0;  i < oi->nmode;  i++)
+        {
+            const XRRModeInfo* mi = getModeInfo(sr, oi->modes[i]);
+            if (!modeIsGood(mi))
+                continue;
+
+            const GLFWvidmode mode = vidmodeFromModeInfo(mi, ci);
+            int j;
+
+            for (j = 0;  j < *count;  j++)
+            {
+                if (_glfwCompareVideoModes(result + j, &mode) == 0)
+                    break;
+            }
+
+            // Skip duplicate modes
+            if (j < *count)
+                continue;
+
+            (*count)++;
+            result[*count - 1] = mode;
+        }
+
+        XRRFreeOutputInfo(oi);
+        XRRFreeCrtcInfo(ci);
+        XRRFreeScreenResources(sr);
+    }
+    else
+    {
+        *count = 1;
+        result = calloc(1, sizeof(GLFWvidmode));
+        _glfwPlatformGetVideoMode(monitor, result);
+    }
+
+    return result;
+}
+
+void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode)
+{
+    if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
+    {
+        XRRScreenResources* sr =
+            XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
+        XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
+
+        if (ci)
+        {
+            const XRRModeInfo* mi = getModeInfo(sr, ci->mode);
+            if (mi)  // mi can be NULL if the monitor has been disconnected
+                *mode = vidmodeFromModeInfo(mi, ci);
+
+            XRRFreeCrtcInfo(ci);
+        }
+
+        XRRFreeScreenResources(sr);
+    }
+    else
+    {
+        mode->width = DisplayWidth(_glfw.x11.display, _glfw.x11.screen);
+        mode->height = DisplayHeight(_glfw.x11.display, _glfw.x11.screen);
+        mode->refreshRate = 0;
+
+        _glfwSplitBPP(DefaultDepth(_glfw.x11.display, _glfw.x11.screen),
+                      &mode->redBits, &mode->greenBits, &mode->blueBits);
+    }
+}
+
+GLFWbool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
+{
+    if (_glfw.x11.randr.available && !_glfw.x11.randr.gammaBroken)
+    {
+        const size_t size = XRRGetCrtcGammaSize(_glfw.x11.display,
+                                                monitor->x11.crtc);
+        XRRCrtcGamma* gamma = XRRGetCrtcGamma(_glfw.x11.display,
+                                              monitor->x11.crtc);
+
+        _glfwAllocGammaArrays(ramp, size);
+
+        memcpy(ramp->red,   gamma->red,   size * sizeof(unsigned short));
+        memcpy(ramp->green, gamma->green, size * sizeof(unsigned short));
+        memcpy(ramp->blue,  gamma->blue,  size * sizeof(unsigned short));
+
+        XRRFreeGamma(gamma);
+        return GLFW_TRUE;
+    }
+    else if (_glfw.x11.vidmode.available)
+    {
+        int size;
+        XF86VidModeGetGammaRampSize(_glfw.x11.display, _glfw.x11.screen, &size);
+
+        _glfwAllocGammaArrays(ramp, size);
+
+        XF86VidModeGetGammaRamp(_glfw.x11.display,
+                                _glfw.x11.screen,
+                                ramp->size, ramp->red, ramp->green, ramp->blue);
+        return GLFW_TRUE;
+    }
+    else
+    {
+        _glfwInputError(GLFW_PLATFORM_ERROR,
+                        "X11: Gamma ramp access not supported by server");
+        return GLFW_FALSE;
+    }
+}
+
+void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp)
+{
+    if (_glfw.x11.randr.available && !_glfw.x11.randr.gammaBroken)
+    {
+        if (XRRGetCrtcGammaSize(_glfw.x11.display, monitor->x11.crtc) != ramp->size)
+        {
+            _glfwInputError(GLFW_PLATFORM_ERROR,
+                            "X11: Gamma ramp size must match current ramp size");
+            return;
+        }
+
+        XRRCrtcGamma* gamma = XRRAllocGamma(ramp->size);
+
+        memcpy(gamma->red,   ramp->red,   ramp->size * sizeof(unsigned short));
+        memcpy(gamma->green, ramp->green, ramp->size * sizeof(unsigned short));
+        memcpy(gamma->blue,  ramp->blue,  ramp->size * sizeof(unsigned short));
+
+        XRRSetCrtcGamma(_glfw.x11.display, monitor->x11.crtc, gamma);
+        XRRFreeGamma(gamma);
+    }
+    else if (_glfw.x11.vidmode.available)
+    {
+        XF86VidModeSetGammaRamp(_glfw.x11.display,
+                                _glfw.x11.screen,
+                                ramp->size,
+                                (unsigned short*) ramp->red,
+                                (unsigned short*) ramp->green,
+                                (unsigned short*) ramp->blue);
+    }
+    else
+    {
+        _glfwInputError(GLFW_PLATFORM_ERROR,
+                        "X11: Gamma ramp access not supported by server");
+    }
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+//////                        GLFW native API                       //////
+//////////////////////////////////////////////////////////////////////////
+
+GLFWAPI RRCrtc glfwGetX11Adapter(GLFWmonitor* handle)
+{
+    _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
+    _GLFW_REQUIRE_INIT_OR_RETURN(None);
+    return monitor->x11.crtc;
+}
+
+GLFWAPI RROutput glfwGetX11Monitor(GLFWmonitor* handle)
+{
+    _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
+    _GLFW_REQUIRE_INIT_OR_RETURN(None);
+    return monitor->x11.output;
+}
+