VirtualBox

Ignore:
Timestamp:
Feb 10, 2020 2:56:41 PM (5 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
136057
Message:

bugref:9637. Updating svga-display-x11 to use xrandr directly.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Additions/x11/VBoxClient/display-svga-x11.cpp

    r82968 r83035  
    3737 *  - When VMSVGA is not enabled, VBoxClient --vmsvga should never stay running.
    3838 */
    39 
     39#include "stdio.h"
    4040#include "VBoxClient.h"
    4141
     
    5757
    5858#include <X11/Xlibint.h>
     59#include <X11/extensions/Xrandr.h>
     60
     61#ifdef RT_OS_LINUX
     62# include <sys/ioctl.h>
     63#else  /* Solaris and BSDs, in case they ever adopt the DRM driver. */
     64# include <sys/ioccom.h>
     65#endif
     66
     67#define USE_XRANDR_BIN
     68
     69
     70struct X11VMWRECT /* xXineramaScreenInfo in Xlib headers. */
     71{
     72    int16_t x;
     73    int16_t y;
     74    uint16_t w;
     75    uint16_t h;
     76};
     77AssertCompileSize(struct X11VMWRECT, 8);
     78
     79struct X11CONTEXT
     80{
     81    Display *pDisplay;
     82    int hRandRMajor;
     83    int hVMWMajor;
     84    int hRandRMinor;
     85    int hRandREventBase;
     86    int hRandRErrorBase;
     87    Window rootWindow;
     88};
     89
     90static void x11Connect(struct X11CONTEXT *pContext)
     91{
     92    int dummy;
     93
     94    if (pContext->pDisplay != NULL)
     95        VBClLogFatalError("%s called with bad argument\n", __func__);
     96    pContext->pDisplay = XOpenDisplay(NULL);
     97    if (pContext->pDisplay == NULL)
     98        return;
     99    // if (   !XQueryExtension(pContext->pDisplay, "RANDR",
     100    //                         &pContext->hRandRMajor, &dummy, &dummy)
     101    if(!XQueryExtension(pContext->pDisplay, "VMWARE_CTRL",
     102                        &pContext->hVMWMajor, &dummy, &dummy))
     103    {
     104        XCloseDisplay(pContext->pDisplay);
     105        pContext->pDisplay = NULL;
     106    }
     107    if (!XRRQueryExtension(pContext->pDisplay, &pContext->hRandREventBase, &pContext->hRandRErrorBase))
     108    {
     109        XCloseDisplay(pContext->pDisplay);
     110        pContext->pDisplay = NULL;
     111    }
     112    if (!XRRQueryVersion(pContext->pDisplay, &pContext->hRandRMajor, &pContext->hRandRMinor))
     113    {
     114        XCloseDisplay(pContext->pDisplay);
     115        pContext->pDisplay = NULL;
     116    }
     117    pContext->rootWindow = DefaultRootWindow(pContext->pDisplay);
     118}
     119
     120#ifndef USE_XRANDR_BIN
    59121
    60122static bool checkRecentLinuxKernel(void)
     
    69131}
    70132
    71 struct X11CONTEXT
    72 {
    73     Display *pDisplay;
    74     int hRandRMajor;
    75     int hVMWMajor;
    76 };
    77 
    78 static void x11Connect(struct X11CONTEXT *pContext)
    79 {
    80     int dummy;
    81 
    82     if (pContext->pDisplay != NULL)
    83         VBClLogFatalError("%s called with bad argument\n", __func__);
    84     pContext->pDisplay = XOpenDisplay(NULL);
    85     if (pContext->pDisplay == NULL)
    86         return;
    87     if (   !XQueryExtension(pContext->pDisplay, "RANDR",
    88                             &pContext->hRandRMajor, &dummy, &dummy)
    89         || !XQueryExtension(pContext->pDisplay, "VMWARE_CTRL",
    90                             &pContext->hVMWMajor, &dummy, &dummy))
    91     {
    92         XCloseDisplay(pContext->pDisplay);
    93         pContext->pDisplay = NULL;
    94     }
    95 }
    96133
    97134#define X11_VMW_TOPOLOGY_REQ 2
    98 struct X11VMWRECT /* xXineramaScreenInfo in Xlib headers. */
    99 {
    100     int16_t x;
    101     int16_t y;
    102     uint16_t w;
    103     uint16_t h;
    104 };
    105 AssertCompileSize(struct X11VMWRECT, 8);
    106135
    107136struct X11REQHEADER
     
    225254}
    226255
     256#else //#fndef USE_XRANDR_BIN
     257
     258#define MAX_MODE_NAME_LEN 64
     259#define MAX_COMMAND_LINE_LEN 512
     260#define MAX_MODE_LINE_LEN 512
     261
     262static const char *szDefaultOutputNamePrefix = "Virtual";
     263static const char *pcszXrandr = "xrandr";
     264static const char *pcszCvt = "cvt";
     265/** The number of outputs (monitors, including disconnect ones) xrandr reports. */
     266static int iOutputCount = 0;
     267
     268struct DRMCONTEXT
     269{
     270    RTFILE hDevice;
     271};
     272
     273#define DRM_DRIVER_NAME "vmwgfx"
     274
     275/** DRM version structure. */
     276struct DRMVERSION
     277{
     278    int cMajor;
     279    int cMinor;
     280    int cPatchLevel;
     281    size_t cbName;
     282    char *pszName;
     283    size_t cbDate;
     284    char *pszDate;
     285    size_t cbDescription;
     286    char *pszDescription;
     287};
     288AssertCompileSize(struct DRMVERSION, 8 + 7 * sizeof(void *));
     289
     290#define DRM_IOCTL_VERSION _IOWR('d', 0x00, struct DRMVERSION)
     291
     292/** Rectangle structure for geometry of a single screen. */
     293struct DRMVMWRECT
     294{
     295        int32_t x;
     296        int32_t y;
     297        uint32_t w;
     298        uint32_t h;
     299};
     300AssertCompileSize(struct DRMVMWRECT, 16);
     301
     302struct DRMVMWUPDATELAYOUT {
     303        uint32_t cOutputs;
     304        uint32_t u32Pad;
     305        uint64_t ptrRects;
     306};
     307AssertCompileSize(struct DRMVMWUPDATELAYOUT, 16);
     308
     309#define DRM_IOCTL_VMW_UPDATE_LAYOUT \
     310        _IOW('d', 0x40 + 20, struct DRMVMWUPDATELAYOUT)
     311
     312struct RANDROUTPUT
     313{
     314    int32_t x;
     315    int32_t y;
     316    uint32_t width;
     317    uint32_t height;
     318    bool fEnabled;
     319};
     320
     321/** run the xrandr command without options to get the total # of outputs (monitors) including
     322 *  disbaled ones. */
     323static int determineOutputCount()
     324{
     325    int iCount = 0;
     326    char szCommand[MAX_COMMAND_LINE_LEN];
     327    RTStrPrintf(szCommand, sizeof(szCommand), "%s ", pcszXrandr);
     328
     329    FILE *pFile;
     330    pFile = popen(szCommand, "r");
     331    if (pFile == NULL)
     332    {
     333        VBClLogError("Failed to run %s\n", szCommand);
     334        return VMW_MAX_HEADS;
     335    }
     336    char szModeLine[MAX_COMMAND_LINE_LEN];
     337    while (fgets(szModeLine, sizeof(szModeLine), pFile) != NULL)
     338    {
     339        if (RTStrIStr(szModeLine, szDefaultOutputNamePrefix))
     340            ++iCount;
     341    }
     342    if (iCount == 0)
     343        iCount = VMW_MAX_HEADS;
     344    return iCount;
     345}
     346
     347/** Parse a single line of the output of xrandr command to extract Mode name.
     348 * Assumed to be null terminated and in following format:
     349 * e.g. 1016x559_vbox  59.70. where 1016x559_vbox is the mode name and at least one space in front
     350 * Set  mode name @p outPszModeName and return true if the name can be found, false otherwise.
     351 * outPszModeNameis assumed to be of length MAX_MODE_NAME_LEN. */
     352static bool parseModeLine(char *pszLine, char *outPszModeName)
     353{
     354    char *p = pszLine;
     355    (void*)outPszModeName;
     356    /* Copy chars to outPszModeName starting from the first non-space until outPszModeName ends with 'vbox'*/
     357    size_t iNameIndex = 0;
     358    bool fInitialSpace = true;
     359
     360    while(*p)
     361    {
     362        if (*p != ' ')
     363            fInitialSpace = false;
     364        if (!fInitialSpace && iNameIndex < MAX_MODE_NAME_LEN)
     365        {
     366            outPszModeName[iNameIndex] = *p;
     367            ++iNameIndex;
     368            if (iNameIndex >= 4)
     369            {
     370                if (outPszModeName[iNameIndex-1] == 'x' &&
     371                    outPszModeName[iNameIndex-2] == 'o' &&
     372                    outPszModeName[iNameIndex-3] == 'b')
     373                    break;
     374            }
     375        }
     376        ++p;
     377    }
     378    outPszModeName[iNameIndex] = '\0';
     379    return true;
     380}
     381
     382/** Parse the output of the xrandr command to try to remove custom modes.
     383 * This function assumes all the outputs are named as VirtualX. */
     384static void removeCustomModesFromOutputs()
     385{
     386    char szCommand[MAX_COMMAND_LINE_LEN];
     387    RTStrPrintf(szCommand, sizeof(szCommand), "%s ", pcszXrandr);
     388
     389    FILE *pFile;
     390    pFile = popen(szCommand, "r");
     391    if (pFile == NULL)
     392    {
     393        VBClLogError("Failed to run %s\n", szCommand);
     394        return;
     395    }
     396    char szModeLine[MAX_COMMAND_LINE_LEN];
     397    char szModeName[MAX_MODE_NAME_LEN];
     398    int iCount = 0;
     399    char szRmModeCommand[MAX_COMMAND_LINE_LEN];
     400    char szDelModeCommand[MAX_COMMAND_LINE_LEN];
     401
     402    while (fgets(szModeLine, sizeof(szModeLine), pFile) != NULL)
     403    {
     404        if (RTStrIStr(szModeLine, szDefaultOutputNamePrefix))
     405        {
     406            ++iCount;
     407            continue;
     408        }
     409        if (iCount > 0 && RTStrIStr(szModeLine, "_vbox"))
     410        {
     411            parseModeLine(szModeLine, szModeName);
     412            if (strlen(szModeName) >= 4)
     413            {
     414                /* Delete the mode from the outout. this fails if the mode is currently in use. */
     415                RTStrPrintf(szDelModeCommand, sizeof(szDelModeCommand), "%s --delmode Virtual%d %s", pcszXrandr, iCount, szModeName);
     416                system(szDelModeCommand);
     417                /* Delete the mode from the xserver. note that this will fail if some output has still has this mode (even if unused).
     418                 * thus this will fail most of the time. */
     419                RTStrPrintf(szRmModeCommand, sizeof(szRmModeCommand), "%s --rmmode %s", pcszXrandr, szModeName);
     420                system(szRmModeCommand);
     421            }
     422        }
     423    }
     424}
     425
     426static void getModeNameAndLineFromCVT(int iWidth, int iHeight, char *pszOutModeName, char *pszOutModeLine)
     427{
     428    char szCvtCommand[MAX_COMMAND_LINE_LEN];
     429    const int iFreq = 60;
     430    const int iMinNameLen = 4;
     431    RTStrPrintf(szCvtCommand, sizeof(szCvtCommand), "%s %d %d %d", pcszCvt, iWidth, iHeight, iFreq);
     432    FILE *pFile;
     433    pFile = popen(szCvtCommand, "r");
     434    if (pFile == NULL)
     435    {
     436        VBClLogError("Failed to run %s\n", szCvtCommand);
     437        return;
     438    }
     439
     440    char szModeLine[MAX_COMMAND_LINE_LEN];
     441    while (fgets(szModeLine, sizeof(szModeLine), pFile) != NULL)
     442    {
     443        if (RTStrStr(szModeLine, "Modeline"))
     444        {
     445            if(szModeLine[strlen(szModeLine) - 1] == '\n')
     446                szModeLine[strlen(szModeLine) - 1] = '\0';
     447            size_t iFirstQu = RTStrOffCharOrTerm(szModeLine, '\"');
     448            size_t iModeLineLen = strlen(szModeLine);
     449            Assert(iFirstQu < iModeLineLen - iMinNameLen);
     450
     451            char *p = &(szModeLine[iFirstQu + 1]);
     452            size_t iSecondQu = RTStrOffCharOrTerm(p, '_');
     453            Assert(iSecondQu > iMinNameLen);
     454            Assert(iSecondQu < MAX_MODE_NAME_LEN);
     455            Assert(iSecondQu < iModeLineLen);
     456
     457            RTStrCopy(pszOutModeName, iSecondQu + 2, p);
     458            RTStrCat(pszOutModeName, MAX_MODE_NAME_LEN, "vbox");
     459            iSecondQu = RTStrOffCharOrTerm(p, '\"');
     460            RTStrCopy(pszOutModeLine, MAX_MODE_LINE_LEN, &(szModeLine[iFirstQu + iSecondQu + 2]));
     461            break;
     462        }
     463    }
     464}
     465
     466/** Add a new mode to xserver and to the output */
     467static void addMode(const char *pszModeName, const char *pszModeLine)
     468{
     469    char szNewModeCommand[MAX_COMMAND_LINE_LEN];
     470    RTStrPrintf(szNewModeCommand, sizeof(szNewModeCommand), "%s --newmode \"%s\" %s", pcszXrandr, pszModeName, pszModeLine);
     471    system(szNewModeCommand);
     472
     473    char szAddModeCommand[1024];
     474    /* try to add the new mode to all possible outputs. we currently dont care if most the are disabled. */
     475    for(int i = 0; i < iOutputCount; ++i)
     476    {
     477        RTStrPrintf(szAddModeCommand, sizeof(szAddModeCommand), "%s --addmode Virtual%d \"%s\"", pcszXrandr, i + 1, pszModeName);
     478        system(szAddModeCommand);
     479    }
     480}
     481
     482static bool checkDefaultModes(struct RANDROUTPUT *pOutput, int iOutputIndex, char *pszModeName)
     483{
     484    const char szError[] = "cannot find mode";
     485    char szXranrCommand[MAX_COMMAND_LINE_LEN];
     486    RTStrPrintf(szXranrCommand, sizeof(szXranrCommand),
     487                "%s --dryrun --output Virtual%u --mode %dx%d --pos %dx%d 2>/dev/stdout", pcszXrandr, iOutputIndex,
     488                pOutput->width, pOutput->height, pOutput->x, pOutput->y);
     489    RTStrPrintf(pszModeName, MAX_MODE_NAME_LEN, "%dx%d", pOutput->width, pOutput->height);
     490    FILE *pFile;
     491    pFile = popen(szXranrCommand, "r");
     492    if (pFile == NULL)
     493    {
     494        VBClLogError("Failed to run %s\n", szXranrCommand);
     495        return false;
     496    }
     497    char szResult[64];
     498    if (fgets(szResult, sizeof(szResult), pFile) != NULL)
     499    {
     500        if (RTStrIStr(szResult, szError))
     501            return false;
     502    }
     503    return true;
     504}
     505
     506/** Construct the xrandr command which sets the whole monitor topology each time. */
     507static void setXrandrModes(struct RANDROUTPUT *paOutputs)
     508{
     509    char szCommand[MAX_COMMAND_LINE_LEN];
     510    RTStrPrintf(szCommand, sizeof(szCommand), "%s ", pcszXrandr);
     511
     512    for (int i = 0; i < iOutputCount; ++i)
     513    {
     514        char line[64];
     515        if (!paOutputs[i].fEnabled)
     516            RTStrPrintf(line, sizeof(line), "--output Virtual%u --off ", i + 1);
     517        else
     518        {
     519            char szModeName[MAX_MODE_NAME_LEN];
     520            char szModeLine[MAX_MODE_LINE_LEN];
     521            /* Check if there is a default mode for the widthxheight and if not create and add a custom mode. */
     522            if (!checkDefaultModes(&(paOutputs[i]), i + 1, szModeName))
     523            {
     524                getModeNameAndLineFromCVT(paOutputs[i].width, paOutputs[i].height, szModeName, szModeLine);
     525                addMode(szModeName, szModeLine);
     526            }
     527            else
     528                RTStrPrintf(szModeName, sizeof(szModeName), "%dx%d ", paOutputs[i].width, paOutputs[i].height);
     529
     530            RTStrPrintf(line, sizeof(line), "--output Virtual%u --mode %s --pos %dx%d ", i + 1,
     531                        szModeName, paOutputs[i].x, paOutputs[i].y);
     532        }
     533        RTStrCat(szCommand, sizeof(szCommand), line);
     534    }
     535    system(szCommand);
     536    VBClLogInfo("=======xrandr topology command:=====\n%s\n", szCommand);
     537    removeCustomModesFromOutputs();
     538}
     539
     540static void drmConnect(struct DRMCONTEXT *pContext)
     541{
     542    unsigned i;
     543    RTFILE hDevice;
     544
     545    if (pContext->hDevice != NIL_RTFILE)
     546        VBClLogFatalError("%s called with bad argument\n", __func__);
     547    /* Try to open the SVGA DRM device. */
     548    for (i = 0; i < 128; ++i)
     549    {
     550        char szPath[64];
     551        struct DRMVERSION version;
     552        char szName[sizeof(DRM_DRIVER_NAME)];
     553        int rc;
     554
     555        /* Control devices for drm graphics driver control devices go from
     556         * controlD64 to controlD127.  Render node devices go from renderD128
     557         * to renderD192.  The driver takes resize hints via the control device
     558         * on pre-4.10 kernels and on the render device on newer ones.  Try
     559         * both types. */
     560        if (i % 2 == 0)
     561            rc = RTStrPrintf(szPath, sizeof(szPath), "/dev/dri/renderD%u", i / 2 + 128);
     562        else
     563            rc = RTStrPrintf(szPath, sizeof(szPath), "/dev/dri/controlD%u", i / 2 + 64);
     564        if (RT_FAILURE(rc))
     565            VBClLogFatalError("RTStrPrintf of device path failed, rc=%Rrc\n", rc);
     566        rc = RTFileOpen(&hDevice, szPath, RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
     567        if (RT_FAILURE(rc))
     568            continue;
     569        RT_ZERO(version);
     570        version.cbName = sizeof(szName);
     571        version.pszName = szName;
     572        rc = RTFileIoCtl(hDevice, DRM_IOCTL_VERSION, &version, sizeof(version), NULL);
     573        if (   RT_SUCCESS(rc)
     574            && !strncmp(szName, DRM_DRIVER_NAME, sizeof(DRM_DRIVER_NAME) - 1)
     575            && (   version.cMajor > 2
     576                || (version.cMajor == 2 && version.cMinor >= 9)))
     577            break;
     578        hDevice = NIL_RTFILE;
     579    }
     580    pContext->hDevice = hDevice;
     581}
     582
     583static void drmSendHints(struct DRMCONTEXT *pContext, struct DRMVMWRECT *paRects,
     584                         unsigned cHeads)
     585{
     586    int rc;
     587    struct DRMVMWUPDATELAYOUT ioctlLayout;
     588
     589    if (pContext->hDevice == NIL_RTFILE)
     590        VBClLogFatalError("%s bad device argument\n", __func__);
     591    ioctlLayout.cOutputs = cHeads;
     592    ioctlLayout.ptrRects = (uint64_t)paRects;
     593    rc = RTFileIoCtl(pContext->hDevice, DRM_IOCTL_VMW_UPDATE_LAYOUT,
     594                     &ioctlLayout, sizeof(ioctlLayout), NULL);
     595    if (RT_FAILURE(rc) && rc != VERR_INVALID_PARAMETER)
     596        VBClLogFatalError("Failure updating layout, rc=%Rrc\n", rc);
     597}
     598
     599#endif /* #ifndef USE_XRANDR_BIN */
     600
    227601static const char *getName()
    228602{
     
    237611static int run(struct VBCLSERVICE **ppInterface, bool fDaemonised)
    238612{
     613    iOutputCount = determineOutputCount();
    239614    (void)ppInterface;
    240615    (void)fDaemonised;
     616    int rc;
     617    /* Do not acknowledge the first event we query for to pick up old events,
     618     * e.g. from before a guest reboot. */
     619    bool fAck = false;
    241620    struct X11CONTEXT x11Context = { NULL };
    242     unsigned i;
    243     int rc;
    244     struct X11VMWRECT aRects[VMW_MAX_HEADS];
    245     unsigned cHeads;
    246 
    247     if (checkRecentLinuxKernel())
    248         return VINF_SUCCESS;
    249621    x11Connect(&x11Context);
    250622    if (x11Context.pDisplay == NULL)
    251623        return VINF_SUCCESS;
     624
     625#ifndef USE_XRANDR_BIN
     626    unsigned cHeads;
     627    struct X11VMWRECT aRects[VMW_MAX_HEADS];
     628    if (checkRecentLinuxKernel())
     629        return VINF_SUCCESS;
     630#else //#ifndef USE_XRANDR_BIN
     631    static struct VMMDevDisplayDef aMonitors[VMW_MAX_HEADS];
     632    struct DRMCONTEXT drmContext = { NIL_RTFILE };
     633    drmConnect(&drmContext);
     634    if (drmContext.hDevice == NIL_RTFILE)
     635        return VINF_SUCCESS;
     636    unsigned cEnabledMonitors = 0;
     637#endif
     638
    252639    rc = VbglR3CtlFilterMask(VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST, 0);
    253640    if (RT_FAILURE(rc))
     
    258645    if (RT_FAILURE(rc))
    259646        VBClLogFatalError("Failed to register resizing support, rc=%Rrc\n", rc);
     647
     648    int eventMask = RRScreenChangeNotifyMask;
     649    if (x11Context.hRandRMinor >= 2)
     650        eventMask |=  RRCrtcChangeNotifyMask |
     651            RROutputChangeNotifyMask |
     652            RROutputPropertyNotifyMask;
     653    if (x11Context.hRandRMinor >= 4)
     654        eventMask |= RRProviderChangeNotifyMask |
     655            RRProviderPropertyNotifyMask |
     656            RRResourceChangeNotifyMask;
     657    if (x11Context.hRandRMinor >= 6)
     658        eventMask |= RRLeaseNotifyMask;
     659
     660
    260661    for (;;)
    261662    {
     
    266667        /* Query the first size without waiting.  This lets us e.g. pick up
    267668         * the last event before a guest reboot when we start again after. */
    268         rc = VbglR3GetDisplayChangeRequestMulti(VMW_MAX_HEADS, &cDisplaysOut, aDisplays, true);
     669        rc = VbglR3GetDisplayChangeRequestMulti(VMW_MAX_HEADS, &cDisplaysOut, aDisplays, fAck);
     670        fAck = true;
     671
    269672        if (RT_FAILURE(rc))
    270673            VBClLogFatalError("Failed to get display change request, rc=%Rrc\n", rc);
    271674        if (cDisplaysOut > VMW_MAX_HEADS)
    272675            VBClLogFatalError("Display change request contained, rc=%Rrc\n", rc);
    273         for (i = 0, cHeads = 0; i < cDisplaysOut && i < VMW_MAX_HEADS; ++i)
     676#ifndef USE_XRANDR_BIN
     677        for (unsigned i = 0, cHeads = 0; i < cDisplaysOut && i < VMW_MAX_HEADS; ++i)
    274678        {
    275679            if (!(aDisplays[i].fDisplayFlags & VMMDEV_DISPLAY_DISABLED))
     
    292696        x11SendHints(&x11Context, aRects, cHeads);
    293697        x11GetScreenInfo(&x11Context);
    294         rc = VbglR3WaitEvent(VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST, RT_INDEFINITE_WAIT, &events);
     698#else
     699        if (cDisplaysOut > 0)
     700        {
     701            for (unsigned i = 0; i < cDisplaysOut && i < VMW_MAX_HEADS; ++i)
     702            {
     703                uint32_t idDisplay = aDisplays[i].idDisplay;
     704                if (idDisplay >= VMW_MAX_HEADS)
     705                    continue;
     706                aMonitors[idDisplay].fDisplayFlags = aDisplays[i].fDisplayFlags;
     707                if (!(aDisplays[i].fDisplayFlags & VMMDEV_DISPLAY_DISABLED))
     708                {
     709                    if ((idDisplay == 0) || (aDisplays[i].fDisplayFlags & VMMDEV_DISPLAY_ORIGIN))
     710                    {
     711                        aMonitors[idDisplay].xOrigin = aDisplays[i].xOrigin;
     712                        aMonitors[idDisplay].yOrigin = aDisplays[i].yOrigin;
     713                    } else {
     714                        aMonitors[idDisplay].xOrigin = aMonitors[idDisplay - 1].xOrigin + aMonitors[idDisplay - 1].cx;
     715                        aMonitors[idDisplay].yOrigin = aMonitors[idDisplay - 1].yOrigin;
     716                    }
     717                    aMonitors[idDisplay].cx = aDisplays[i].cx;
     718                    aMonitors[idDisplay].cy = aDisplays[i].cy;
     719                }
     720            }
     721
     722            /* Create a whole topology and send it to xrandr. */
     723            struct RANDROUTPUT aOutputs[VMW_MAX_HEADS];
     724            int iRunningX = 0;
     725            for (int j = 0; j < iOutputCount; ++j)
     726            {
     727                aOutputs[j].x = iRunningX;
     728                aOutputs[j].y = aMonitors[j].yOrigin;
     729                aOutputs[j].width = aMonitors[j].cx;
     730                aOutputs[j].height = aMonitors[j].cy;
     731                aOutputs[j].fEnabled = !(aMonitors[j].fDisplayFlags & VMMDEV_DISPLAY_DISABLED);
     732                if (aOutputs[j].fEnabled)
     733                    iRunningX += aOutputs[j].width;
     734            }
     735            setXrandrModes(aOutputs);
     736            /* Disable this for now since we want to fix messed up monitor positions in some other way. */
     737            if(0)
     738            {
     739                /* Additionally update the drm thru ioctl since vmwgfx messes up monitor positions it gets from xserver. */
     740                /* Create an dense (consisting of enabled monitors only) array to pass to DRM. */
     741                cEnabledMonitors = 0;
     742                struct DRMVMWRECT aEnabledMonitors[VMW_MAX_HEADS];
     743                for (int j = 0; j < VMW_MAX_HEADS; ++j)
     744                {
     745                    if (!(aMonitors[j].fDisplayFlags & VMMDEV_DISPLAY_DISABLED))
     746                    {
     747                        aEnabledMonitors[cEnabledMonitors].x = aMonitors[j].xOrigin;
     748                        aEnabledMonitors[cEnabledMonitors].y = aMonitors[j].yOrigin;
     749                        aEnabledMonitors[cEnabledMonitors].w = aMonitors[j].cx;
     750                        aEnabledMonitors[cEnabledMonitors].h = aMonitors[j].cy;
     751                        if (cEnabledMonitors > 0)
     752                            aEnabledMonitors[cEnabledMonitors].x = aEnabledMonitors[cEnabledMonitors - 1].x + aEnabledMonitors[cEnabledMonitors - 1].w;
     753                        ++cEnabledMonitors;
     754                    }
     755                }
     756                bool fScreenChangeNotifyEvent = false;
     757                XRRSelectInput(x11Context.pDisplay, x11Context.rootWindow, eventMask);
     758                XSync(x11Context.pDisplay, false);
     759                XEvent event;
     760                while (XCheckTypedEvent(x11Context.pDisplay, RRScreenChangeNotify + x11Context.hRandREventBase, &event) ||
     761                       XCheckTypedEvent(x11Context.pDisplay, RRNotify + x11Context.hRandREventBase, &event))
     762                    fScreenChangeNotifyEvent = true;
     763                XRRSelectInput(x11Context.pDisplay, x11Context.rootWindow, 0);
     764
     765                if (!fScreenChangeNotifyEvent)
     766                    VBClLogInfo("Did not receive any RRScreenChangeNotify events.\n");
     767                else
     768                    drmSendHints(&drmContext, aEnabledMonitors, cEnabledMonitors);
     769            }
     770        }
     771
     772#endif
     773        do
     774        {
     775            rc = VbglR3WaitEvent(VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST, RT_INDEFINITE_WAIT, &events);
     776        } while (rc == VERR_INTERRUPTED);
    295777        if (RT_FAILURE(rc))
    296778            VBClLogFatalError("Failure waiting for event, rc=%Rrc\n", rc);
Note: See TracChangeset for help on using the changeset viewer.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette