VirtualBox

Changeset 83136 in vbox for trunk/src/VBox/Additions/x11


Ignore:
Timestamp:
Feb 21, 2020 2:36:52 PM (5 years ago)
Author:
vboxsync
Message:

bugref:9637. Adding randr event monitoring to display-svga client.

File:
1 edited

Legend:

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

    r83123 r83136  
    3737 *  - When VMSVGA is not enabled, VBoxClient --vmsvga should never stay running.
    3838 */
    39 #include "stdio.h"
     39#include <stdio.h>
    4040#include "VBoxClient.h"
    4141
     
    4646#include <iprt/file.h>
    4747#include <iprt/string.h>
    48 
    49 #include <sys/utsname.h>
     48#include <iprt/thread.h>
     49
     50#include <X11/Xlib.h>
     51#include <X11/Xutil.h>
     52#include <X11/Xlibint.h>
     53#include <X11/extensions/shape.h>
     54#include <X11/extensions/Xrandr.h>
    5055
    5156/** Maximum number of supported screens.  DRM and X11 both limit this to 32. */
     
    5358 *  context structure. */
    5459#define VMW_MAX_HEADS 32
    55 
    56 #include "seamless-x11.h"
    57 
    58 #ifdef RT_OS_LINUX
    59 # include <sys/ioctl.h>
    60 #else  /* Solaris and BSDs, in case they ever adopt the DRM driver. */
    61 # include <sys/ioccom.h>
    62 #endif
    63 
    64 #define USE_XRANDR_BIN
    65 
     60/** Monitor positions array. Allocated here and deallocated in the class descructor. */
     61RTPOINT *mpMonitorPositions;
     62/** Thread to listen to some of the X server events. */
     63RTTHREAD mX11MonitorThread = NIL_RTTHREAD;
    6664
    6765struct X11VMWRECT /* xXineramaScreenInfo in Xlib headers. */
     
    8381    int hRandRErrorBase;
    8482    int hEventMask;
     83    /** The number of outputs (monitors, including disconnect ones) xrandr reports. */
     84    int hOutputCount;
    8585    Window rootWindow;
    8686};
     87
     88static X11CONTEXT x11Context;
    8789
    8890#define MAX_MODE_NAME_LEN 64
     
    9395static const char *pcszXrandr = "xrandr";
    9496static const char *pcszCvt = "cvt";
    95 /** The number of outputs (monitors, including disconnect ones) xrandr reports. */
    96 static int iOutputCount = 0;
    9797
    9898struct DRMCONTEXT
     
    111111
    112112/** Forward declarations. */
    113 static void x11Connect(struct X11CONTEXT *pContext);
    114 
    115 static bool init(struct X11CONTEXT *pContext)
    116 {
    117     if (!pContext)
     113static void x11Connect();
     114static int determineOutputCount();
     115
     116/** This function assumes monitors are named as from Virtual1 to VirtualX. */
     117static int getMonitorIdFromName(const char *sMonitorName)
     118{
     119    if (!sMonitorName)
     120        return -1;
     121    int iLen = strlen(sMonitorName);
     122    if (iLen <= 0)
     123        return -1;
     124    int iBase = 10;
     125    int iResult = 0;
     126    for (int i = iLen - 1; i >= 0; --i)
     127    {
     128        /* Stop upon seeing the first non-numeric char. */
     129        if (sMonitorName[i] < 48 || sMonitorName[i] > 57)
     130            break;
     131        iResult += (sMonitorName[i] - 48) * iBase / 10;
     132        iBase *= 10;
     133    }
     134    return iResult;
     135}
     136
     137static void queryMonitorPositions()
     138{
     139    printf("===========================================================================================================================================");
     140    static const int iSentinelPosition = -1;
     141    if (mpMonitorPositions)
     142    {
     143        free(mpMonitorPositions);
     144        mpMonitorPositions = NULL;
     145    }
     146    // if (!mHostMonitorPositionSendCallback)
     147    // {
     148    //     VBClLogFatalError("No monitor positions update callback\n");
     149    //     return;
     150    // }
     151
     152    XRRScreenResources *pScreenResources = XRRGetScreenResources (x11Context.pDisplay, DefaultRootWindow(x11Context.pDisplay));
     153    AssertReturnVoid(pScreenResources);
     154    XRRFreeScreenResources (pScreenResources);
     155
     156    int iMonitorCount = 0;
     157    XRRMonitorInfo *pMonitorInfo = XRRGetMonitors(x11Context.pDisplay, DefaultRootWindow(x11Context.pDisplay), true, &iMonitorCount);
     158    if (iMonitorCount == -1)
     159        VBClLogError("Could not get monitor info\n");
     160    else
     161    {
     162        getMonitorIdFromName("virtual123");
     163        mpMonitorPositions = (RTPOINT*)malloc(x11Context.hOutputCount * sizeof(RTPOINT));
     164        /* todo: memset? */
     165        for (int i = 0; i < x11Context.hOutputCount; ++i)
     166        {
     167            mpMonitorPositions[i].x = iSentinelPosition;
     168            mpMonitorPositions[i].y = iSentinelPosition;
     169        }
     170        for (int i = 0; i < iMonitorCount; ++i)
     171        {
     172            int iMonitorID = getMonitorIdFromName(XGetAtomName(x11Context.pDisplay, pMonitorInfo[i].name)) - 1;
     173            if (iMonitorID >= x11Context.hOutputCount || iMonitorID == -1)
     174                continue;
     175            VBClLogInfo("Monitor %d (w,h)=(%d,%d) (x,y)=(%d,%d)\n",
     176                        i,
     177                        pMonitorInfo[i].width, pMonitorInfo[i].height,
     178                        pMonitorInfo[i].x, pMonitorInfo[i].y);
     179            mpMonitorPositions[iMonitorID].x = pMonitorInfo[i].x;
     180            mpMonitorPositions[iMonitorID].y = pMonitorInfo[i].y;
     181        }
     182        // if (iMonitorCount > 0)
     183        //     mHostMonitorPositionSendCallback(mpMonitorPositions, x11Context.hOutputCount);
     184    }
     185    XRRFreeMonitors(pMonitorInfo);
     186}
     187
     188static void monitorRandREvents()
     189{
     190    XEvent event;
     191    XNextEvent(x11Context.pDisplay, &event);
     192    int eventTypeOffset = event.type - x11Context.hRandREventBase;
     193    switch (eventTypeOffset)
     194    {
     195        case RRScreenChangeNotify:
     196            VBClLogInfo("RRScreenChangeNotify\n");
     197            queryMonitorPositions();
     198            break;
     199        case RRNotify:
     200            VBClLogInfo("RRNotify\n");
     201            break;
     202        default:
     203            VBClLogInfo("Unknown RR event\n");
     204            break;
     205    }
     206}
     207
     208int x11MonitorThreadFunction(RTTHREAD hThreadSelf, void *pvUser)
     209{
     210    (void)hThreadSelf;
     211    (void*)pvUser;
     212    while(1)
     213    {
     214        monitorRandREvents();
     215    }
     216    return 0;
     217}
     218
     219static int startX11MonitorThread()
     220{
     221    int rc;
     222
     223    if (mX11MonitorThread == NIL_RTTHREAD)
     224    {
     225        rc = RTThreadCreate(&mX11MonitorThread, x11MonitorThreadFunction, 0, 0,
     226                            RTTHREADTYPE_MSG_PUMP, RTTHREADFLAGS_WAITABLE,
     227                            "X11 events");
     228        if (RT_FAILURE(rc))
     229            VBClLogFatalError("Warning: failed to start X11 monitor thread (VBoxClient) rc=%Rrc!\n", rc);
     230    }
     231    return rc;
     232}
     233
     234static int stopX11MonitorThread(void)
     235{
     236    int rc;
     237    if (mX11MonitorThread != NIL_RTTHREAD)
     238    {
     239        //????????
     240        //mX11Monitor.interruptEventWait();
     241        rc = RTThreadWait(mX11MonitorThread, 1000, NULL);
     242        if (RT_SUCCESS(rc))
     243            mX11MonitorThread = NIL_RTTHREAD;
     244        else
     245            VBClLogError("Failed to stop X11 monitor thread, rc=%Rrc!\n", rc);
     246    }
     247    return rc;
     248}
     249
     250static bool init()
     251{
     252    x11Connect();
     253    if (x11Context.pDisplay == NULL)
    118254        return false;
    119     x11Connect(pContext);
    120     if (pContext->pDisplay == NULL)
     255    if (RT_FAILURE(startX11MonitorThread()))
    121256        return false;
     257    XRRSelectInput(x11Context.pDisplay, x11Context.rootWindow, x11Context.hEventMask);
    122258    return true;
    123259}
    124260
    125 static void x11Connect(struct X11CONTEXT *pContext)
     261static void cleanup()
     262{
     263    if (mpMonitorPositions)
     264    {
     265        free(mpMonitorPositions);
     266        mpMonitorPositions = NULL;
     267    }
     268    stopX11MonitorThread();
     269    XRRSelectInput(x11Context.pDisplay, x11Context.rootWindow, 0);
     270    XCloseDisplay(x11Context.pDisplay);
     271}
     272
     273static void x11Connect()
    126274{
    127275    int dummy;
    128     if (pContext->pDisplay != NULL)
     276    if (x11Context.pDisplay != NULL)
    129277        VBClLogFatalError("%s called with bad argument\n", __func__);
    130     pContext->pDisplay = XOpenDisplay(NULL);
    131     if (pContext->pDisplay == NULL)
     278    x11Context.pDisplay = XOpenDisplay(NULL);
     279    if (x11Context.pDisplay == NULL)
    132280        return;
    133     if(!XQueryExtension(pContext->pDisplay, "VMWARE_CTRL",
    134                         &pContext->hVMWMajor, &dummy, &dummy))
    135     {
    136         XCloseDisplay(pContext->pDisplay);
    137         pContext->pDisplay = NULL;
    138     }
    139     if (!XRRQueryExtension(pContext->pDisplay, &pContext->hRandREventBase, &pContext->hRandRErrorBase))
    140     {
    141         XCloseDisplay(pContext->pDisplay);
    142         pContext->pDisplay = NULL;
    143     }
    144     if (!XRRQueryVersion(pContext->pDisplay, &pContext->hRandRMajor, &pContext->hRandRMinor))
    145     {
    146         XCloseDisplay(pContext->pDisplay);
    147         pContext->pDisplay = NULL;
    148     }
    149     pContext->hEventMask = RRScreenChangeNotifyMask;
    150     if (pContext->hRandRMinor >= 2)
    151         pContext->hEventMask |=  RRCrtcChangeNotifyMask |
     281    if(!XQueryExtension(x11Context.pDisplay, "VMWARE_CTRL",
     282                        &x11Context.hVMWMajor, &dummy, &dummy))
     283    {
     284        XCloseDisplay(x11Context.pDisplay);
     285        x11Context.pDisplay = NULL;
     286    }
     287    if (!XRRQueryExtension(x11Context.pDisplay, &x11Context.hRandREventBase, &x11Context.hRandRErrorBase))
     288    {
     289        XCloseDisplay(x11Context.pDisplay);
     290        x11Context.pDisplay = NULL;
     291    }
     292    if (!XRRQueryVersion(x11Context.pDisplay, &x11Context.hRandRMajor, &x11Context.hRandRMinor))
     293    {
     294        XCloseDisplay(x11Context.pDisplay);
     295        x11Context.pDisplay = NULL;
     296    }
     297    x11Context.hEventMask = RRScreenChangeNotifyMask;
     298    if (x11Context.hRandRMinor >= 2)
     299        x11Context.hEventMask |=  RRCrtcChangeNotifyMask |
    152300            RROutputChangeNotifyMask |
    153301            RROutputPropertyNotifyMask;
    154     pContext->rootWindow = DefaultRootWindow(pContext->pDisplay);
     302    x11Context.rootWindow = DefaultRootWindow(x11Context.pDisplay);
     303    x11Context.hOutputCount = determineOutputCount();
    155304}
    156305
     
    313462    char szAddModeCommand[1024];
    314463    /* try to add the new mode to all possible outputs. we currently dont care if most the are disabled. */
    315     for(int i = 0; i < iOutputCount; ++i)
     464    for(int i = 0; i < x11Context.hOutputCount; ++i)
    316465    {
    317466        RTStrPrintf(szAddModeCommand, sizeof(szAddModeCommand), "%s --addmode Virtual%d \"%s\"", pcszXrandr, i + 1, pszModeName);
     
    350499    RTStrPrintf(szCommand, sizeof(szCommand), "%s ", pcszXrandr);
    351500
    352     for (int i = 0; i < iOutputCount; ++i)
     501    for (int i = 0; i < x11Context.hOutputCount; ++i)
    353502    {
    354503        char line[64];
     
    390539static int run(struct VBCLSERVICE **ppInterface, bool fDaemonised)
    391540{
    392     iOutputCount = determineOutputCount();
    393541    (void)ppInterface;
    394542    (void)fDaemonised;
     
    398546     * e.g. from before a guest reboot. */
    399547    bool fAck = false;
    400     struct X11CONTEXT x11Context = { NULL };
    401     if (!init(&x11Context))
     548
     549    if (!init())
    402550        return VINF_SUCCESS;
    403551    static struct VMMDevDisplayDef aMonitors[VMW_MAX_HEADS];
     
    458606            struct RANDROUTPUT aOutputs[VMW_MAX_HEADS];
    459607            int iRunningX = 0;
    460             for (int j = 0; j < iOutputCount; ++j)
     608            for (int j = 0; j < x11Context.hOutputCount; ++j)
    461609            {
    462610                aOutputs[j].x = iRunningX;
     
    477625            VBClLogFatalError("Failure waiting for event, rc=%Rrc\n", rc);
    478626    }
     627    cleanup();
    479628}
    480629
Note: See TracChangeset for help on using the changeset viewer.

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