123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623 |
- //========================================================================
- // 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 bool 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)
- {
- XRRFreeOutputInfo(oi);
- continue;
- }
- 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 == (short int)ci->width &&
- screens[j].height == (short int)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, ¤t);
- if (_glfwCompareVideoModes(¤t, 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 UNUSED)
- {
- }
- 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 UNUSED,
- 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;
- }
- bool _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode) {
- bool ok = false;
- 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);
- ok = true;
- }
- XRRFreeCrtcInfo(ci);
- }
- XRRFreeScreenResources(sr);
- }
- else
- {
- ok = true;
- 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);
- }
- return ok;
- }
- bool _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 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 true;
- }
- else
- {
- _glfwInputError(GLFW_PLATFORM_ERROR,
- "X11: Gamma ramp access not supported by server");
- return 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) != (int)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;
- }
|