VirtualBox

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


Ignore:
Timestamp:
Apr 21, 2020 7:31:41 PM (5 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
137447
Message:

bugref:9637. Replacing xrandr binary calls with libxrandr ones. not tested.

File:
1 edited

Legend:

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

    r83257 r83910  
    3636 *    screen, and enabling others should not be possible.
    3737 *  - When VMSVGA is not enabled, VBoxClient --vmsvga should never stay running.
     38 *  - The following assumptions are done and should be taken into account when reading/chaning the code:
     39 *    # The order of the outputs (monitors) is assumed to be the same in RANDROUTPUT array and
     40        XRRScreenResources.outputs array.
    3841 */
    3942#include <stdio.h>
     
    5356#include <X11/extensions/Xrandr.h>
    5457#include <X11/extensions/panoramiXproto.h>
     58
     59#define MILLIS_PER_INCH (25.4)
     60#define DEFAULT_DPI (96.0)
     61
    5562
    5663/** Maximum number of supported screens.  DRM and X11 both limit this to 32. */
     
    104111{
    105112    Display *pDisplay;
     113    Window rootWindow;
     114    int iDefaultScreen;
     115    XRRScreenResources *pScreenResources;
    106116    int hRandRMajor;
    107117    int hVMWCtrlMajorOpCode;
     
    112122    /** The number of outputs (monitors, including disconnect ones) xrandr reports. */
    113123    int hOutputCount;
    114     Window rootWindow;
    115124    void *pRandLibraryHandle;
     125    /** Function pointers we used if we dlopen libXrandr instead of linking. */
    116126    void (*pXRRSelectInput) (Display *, Window, int);
    117127    Bool (*pXRRQueryExtension) (Display *, int *, int *);
    118128    Status (*pXRRQueryVersion) (Display *, int *, int*);
    119129    XRRMonitorInfo* (*pXRRGetMonitors)(Display *, Window, Bool, int *);
     130    XRRScreenResources* (*pXRRGetScreenResources)(Display *, Window);
     131    Status (*pXRRSetCrtcConfig)(Display *, XRRScreenResources *, RRCrtc,
     132                                Time, int, int, RRMode, Rotation, RROutput *, int);
    120133    void (*pXRRFreeMonitors)(XRRMonitorInfo *);
     134    void (*pXRRFreeScreenResources)(XRRScreenResources *);
     135    void (*pXRRFreeModeInfo)(XRRModeInfo *);
     136    void (*pXRRFreeOutputInfo)(XRROutputInfo *);
     137    void (*pXRRSetScreenSize)(Display *, Window, int, int, int, int);
     138    int (*pXRRUpdateConfiguration)(XEvent *event);
     139    XRRModeInfo* (*pXRRAllocModeInfo)(_Xconst char *, int);
     140    RRMode (*pXRRCreateMode) (Display *, Window, XRRModeInfo *);
     141    XRROutputInfo* (*pXRRGetOutputInfo) (Display *, XRRScreenResources *, RROutput);
     142    void (*pXRRAddOutputMode)(Display *, RROutput, RRMode);
    121143};
    122144
     
    126148#define MAX_COMMAND_LINE_LEN 512
    127149#define MAX_MODE_LINE_LEN 512
    128 
    129 static const char *szDefaultOutputNamePrefix = "Virtual";
    130 static const char *pcszXrandr = "xrandr";
    131 static const char *pcszCvt = "cvt";
    132150
    133151struct RANDROUTPUT
     
    138156    uint32_t height;
    139157    bool fEnabled;
     158};
     159
     160struct DisplayModeR {
     161
     162    /* These are the values that the user sees/provides */
     163    int Clock;                  /* pixel clock freq (kHz) */
     164    int HDisplay;               /* horizontal timing */
     165    int HSyncStart;
     166    int HSyncEnd;
     167    int HTotal;
     168    int HSkew;
     169    int VDisplay;               /* vertical timing */
     170    int VSyncStart;
     171    int VSyncEnd;
     172    int VTotal;
     173    int VScan;
     174    float HSync;
     175    float VRefresh;
    140176};
    141177
     
    154190        }                                                               \
    155191    }while(0)
     192
     193
     194/** A slightly modified version of the xf86CVTMode function from xf86cvt.c
     195  * from the xserver source code. Computes several parameters of a display mode
     196  * out of horizontal and vertical resolutions. Replicated here to avoid further
     197  * dependencies. */
     198DisplayModeR f86CVTMode(int HDisplay, int VDisplay, float VRefresh, Bool Reduced,
     199            Bool Interlaced)
     200{
     201    DisplayModeR Mode;
     202
     203    /* 1) top/bottom margin size (% of height) - default: 1.8 */
     204#define CVT_MARGIN_PERCENTAGE 1.8
     205
     206    /* 2) character cell horizontal granularity (pixels) - default 8 */
     207#define CVT_H_GRANULARITY 8
     208
     209    /* 4) Minimum vertical porch (lines) - default 3 */
     210#define CVT_MIN_V_PORCH 3
     211
     212    /* 4) Minimum number of vertical back porch lines - default 6 */
     213#define CVT_MIN_V_BPORCH 6
     214
     215    /* Pixel Clock step (kHz) */
     216#define CVT_CLOCK_STEP 250
     217
     218    Bool Margins = false;
     219    float VFieldRate, HPeriod;
     220    int HDisplayRnd, HMargin;
     221    int VDisplayRnd, VMargin, VSync;
     222    float Interlace;            /* Please rename this */
     223
     224    /* CVT default is 60.0Hz */
     225    if (!VRefresh)
     226        VRefresh = 60.0;
     227
     228    /* 1. Required field rate */
     229    if (Interlaced)
     230        VFieldRate = VRefresh * 2;
     231    else
     232        VFieldRate = VRefresh;
     233
     234    /* 2. Horizontal pixels */
     235    HDisplayRnd = HDisplay - (HDisplay % CVT_H_GRANULARITY);
     236
     237    /* 3. Determine left and right borders */
     238    if (Margins) {
     239        /* right margin is actually exactly the same as left */
     240        HMargin = (((float) HDisplayRnd) * CVT_MARGIN_PERCENTAGE / 100.0);
     241        HMargin -= HMargin % CVT_H_GRANULARITY;
     242    }
     243    else
     244        HMargin = 0;
     245
     246    /* 4. Find total active pixels */
     247    Mode.HDisplay = HDisplayRnd + 2 * HMargin;
     248
     249    /* 5. Find number of lines per field */
     250    if (Interlaced)
     251        VDisplayRnd = VDisplay / 2;
     252    else
     253        VDisplayRnd = VDisplay;
     254
     255    /* 6. Find top and bottom margins */
     256    /* nope. */
     257    if (Margins)
     258        /* top and bottom margins are equal again. */
     259        VMargin = (((float) VDisplayRnd) * CVT_MARGIN_PERCENTAGE / 100.0);
     260    else
     261        VMargin = 0;
     262
     263    Mode.VDisplay = VDisplay + 2 * VMargin;
     264
     265    /* 7. Interlace */
     266    if (Interlaced)
     267        Interlace = 0.5;
     268    else
     269        Interlace = 0.0;
     270
     271    /* Determine VSync Width from aspect ratio */
     272    if (!(VDisplay % 3) && ((VDisplay * 4 / 3) == HDisplay))
     273        VSync = 4;
     274    else if (!(VDisplay % 9) && ((VDisplay * 16 / 9) == HDisplay))
     275        VSync = 5;
     276    else if (!(VDisplay % 10) && ((VDisplay * 16 / 10) == HDisplay))
     277        VSync = 6;
     278    else if (!(VDisplay % 4) && ((VDisplay * 5 / 4) == HDisplay))
     279        VSync = 7;
     280    else if (!(VDisplay % 9) && ((VDisplay * 15 / 9) == HDisplay))
     281        VSync = 7;
     282    else                        /* Custom */
     283        VSync = 10;
     284
     285    if (!Reduced) {             /* simplified GTF calculation */
     286
     287        /* 4) Minimum time of vertical sync + back porch interval (µs)
     288         * default 550.0 */
     289#define CVT_MIN_VSYNC_BP 550.0
     290
     291        /* 3) Nominal HSync width (% of line period) - default 8 */
     292#define CVT_HSYNC_PERCENTAGE 8
     293
     294        float HBlankPercentage;
     295        int VSyncAndBackPorch, VBackPorch;
     296        int HBlank;
     297
     298        /* 8. Estimated Horizontal period */
     299        HPeriod = ((float) (1000000.0 / VFieldRate - CVT_MIN_VSYNC_BP)) /
     300            (VDisplayRnd + 2 * VMargin + CVT_MIN_V_PORCH + Interlace);
     301
     302        /* 9. Find number of lines in sync + backporch */
     303        if (((int) (CVT_MIN_VSYNC_BP / HPeriod) + 1) <
     304            (VSync + CVT_MIN_V_PORCH))
     305            VSyncAndBackPorch = VSync + CVT_MIN_V_PORCH;
     306        else
     307            VSyncAndBackPorch = (int) (CVT_MIN_VSYNC_BP / HPeriod) + 1;
     308
     309        /* 10. Find number of lines in back porch */
     310        VBackPorch = VSyncAndBackPorch - VSync;
     311        (void) VBackPorch;
     312
     313        /* 11. Find total number of lines in vertical field */
     314        Mode.VTotal = VDisplayRnd + 2 * VMargin + VSyncAndBackPorch + Interlace
     315            + CVT_MIN_V_PORCH;
     316
     317        /* 5) Definition of Horizontal blanking time limitation */
     318        /* Gradient (%/kHz) - default 600 */
     319#define CVT_M_FACTOR 600
     320
     321        /* Offset (%) - default 40 */
     322#define CVT_C_FACTOR 40
     323
     324        /* Blanking time scaling factor - default 128 */
     325#define CVT_K_FACTOR 128
     326
     327        /* Scaling factor weighting - default 20 */
     328#define CVT_J_FACTOR 20
     329
     330#define CVT_M_PRIME CVT_M_FACTOR * CVT_K_FACTOR / 256
     331#define CVT_C_PRIME (CVT_C_FACTOR - CVT_J_FACTOR) * CVT_K_FACTOR / 256 + \
     332        CVT_J_FACTOR
     333
     334        /* 12. Find ideal blanking duty cycle from formula */
     335        HBlankPercentage = CVT_C_PRIME - CVT_M_PRIME * HPeriod / 1000.0;
     336
     337        /* 13. Blanking time */
     338        if (HBlankPercentage < 20)
     339            HBlankPercentage = 20;
     340
     341        HBlank = Mode.HDisplay * HBlankPercentage / (100.0 - HBlankPercentage);
     342        HBlank -= HBlank % (2 * CVT_H_GRANULARITY);
     343
     344        /* 14. Find total number of pixels in a line. */
     345        Mode.HTotal = Mode.HDisplay + HBlank;
     346
     347        /* Fill in HSync values */
     348        Mode.HSyncEnd = Mode.HDisplay + HBlank / 2;
     349
     350        Mode.HSyncStart = Mode.HSyncEnd -
     351            (Mode.HTotal * CVT_HSYNC_PERCENTAGE) / 100;
     352        Mode.HSyncStart += CVT_H_GRANULARITY -
     353            Mode.HSyncStart % CVT_H_GRANULARITY;
     354
     355        /* Fill in VSync values */
     356        Mode.VSyncStart = Mode.VDisplay + CVT_MIN_V_PORCH;
     357        Mode.VSyncEnd = Mode.VSyncStart + VSync;
     358
     359    }
     360    else {                      /* Reduced blanking */
     361        /* Minimum vertical blanking interval time (µs) - default 460 */
     362#define CVT_RB_MIN_VBLANK 460.0
     363
     364        /* Fixed number of clocks for horizontal sync */
     365#define CVT_RB_H_SYNC 32.0
     366
     367        /* Fixed number of clocks for horizontal blanking */
     368#define CVT_RB_H_BLANK 160.0
     369
     370        /* Fixed number of lines for vertical front porch - default 3 */
     371#define CVT_RB_VFPORCH 3
     372
     373        int VBILines;
     374
     375        /* 8. Estimate Horizontal period. */
     376        HPeriod = ((float) (1000000.0 / VFieldRate - CVT_RB_MIN_VBLANK)) /
     377            (VDisplayRnd + 2 * VMargin);
     378
     379        /* 9. Find number of lines in vertical blanking */
     380        VBILines = ((float) CVT_RB_MIN_VBLANK) / HPeriod + 1;
     381
     382        /* 10. Check if vertical blanking is sufficient */
     383        if (VBILines < (CVT_RB_VFPORCH + VSync + CVT_MIN_V_BPORCH))
     384            VBILines = CVT_RB_VFPORCH + VSync + CVT_MIN_V_BPORCH;
     385
     386        /* 11. Find total number of lines in vertical field */
     387        Mode.VTotal = VDisplayRnd + 2 * VMargin + Interlace + VBILines;
     388
     389        /* 12. Find total number of pixels in a line */
     390        Mode.HTotal = Mode.HDisplay + CVT_RB_H_BLANK;
     391
     392        /* Fill in HSync values */
     393        Mode.HSyncEnd = Mode.HDisplay + CVT_RB_H_BLANK / 2;
     394        Mode.HSyncStart = Mode.HSyncEnd - CVT_RB_H_SYNC;
     395
     396        /* Fill in VSync values */
     397        Mode.VSyncStart = Mode.VDisplay + CVT_RB_VFPORCH;
     398        Mode.VSyncEnd = Mode.VSyncStart + VSync;
     399    }
     400    /* 15/13. Find pixel clock frequency (kHz for xf86) */
     401    Mode.Clock = Mode.HTotal * 1000.0 / HPeriod;
     402    Mode.Clock -= Mode.Clock % CVT_CLOCK_STEP;
     403
     404    /* 16/14. Find actual Horizontal Frequency (kHz) */
     405    Mode.HSync = ((float) Mode.Clock) / ((float) Mode.HTotal);
     406
     407    /* 17/15. Find actual Field rate */
     408    Mode.VRefresh = (1000.0 * ((float) Mode.Clock)) /
     409        ((float) (Mode.HTotal * Mode.VTotal));
     410
     411    /* 18/16. Find actual vertical frame frequency */
     412    /* ignore - just set the mode flag for interlaced */
     413    if (Interlaced)
     414        Mode.VTotal *= 2;
     415    return Mode;
     416}
     417
    156418
    157419bool VMwareCtrlSetTopology(Display *dpy, int hExtensionMajorOpcode,
     
    312574static int startX11MonitorThread()
    313575{
     576    return 0;
    314577    int rc;
    315578
     
    396659#ifdef WITH_DISTRO_XRAND_XINERAMA
    397660    XRRSelectInput(x11Context.pDisplay, x11Context.rootWindow, 0);
     661    XRRFreeScreenResources(x11Context.pScreenResources);
    398662#else
    399663    if (x11Context.pXRRSelectInput)
    400664        x11Context.pXRRSelectInput(x11Context.pDisplay, x11Context.rootWindow, 0);
     665    if (x11Context.pXRRFreeScreenResources)
     666        x11Context.pXRRFreeScreenResources(x11Context.pScreenResources);
    401667#endif
    402668    XCloseDisplay(x11Context.pDisplay);
     
    430696    checkFunctionPtr(x11Context.pXRRGetMonitors);
    431697
     698    *(void **)(&x11Context.pXRRGetScreenResources) = dlsym(x11Context.pRandLibraryHandle, "XRRGetScreenResources");
     699    checkFunctionPtr(x11Context.pXRRGetScreenResources);
     700
     701    *(void **)(&x11Context.pXRRSetCrtcConfig) = dlsym(x11Context.pRandLibraryHandle, "XRRSetCrtcConfig");
     702    checkFunctionPtr(x11Context.pXRRSetCrtcConfig);
     703
    432704    *(void **)(&x11Context.pXRRFreeMonitors) = dlsym(x11Context.pRandLibraryHandle, "XRRFreeMonitors");
    433705    checkFunctionPtr(x11Context.pXRRFreeMonitors);
    434706
     707    *(void **)(&x11Context.pXRRFreeScreenResources) = dlsym(x11Context.pRandLibraryHandle, "XRRFreeScreenResources");
     708    checkFunctionPtr(x11Context.pXRRFreeMonitors);
     709
     710    *(void **)(&x11Context.pXRRFreeModeInfo) = dlsym(x11Context.pRandLibraryHandle, "XRRFreeModeInfo");
     711    checkFunctionPtr(x11Context.pXRRFreeModeInfo);
     712
     713    *(void **)(&x11Context.pXRRFreeOutputInfo) = dlsym(x11Context.pRandLibraryHandle, "XRRFreeOutputInfo");
     714    checkFunctionPtr(x11Context.pXRRFreeOutputInfo);
     715
     716    *(void **)(&x11Context.pXRRSetScreenSize) = dlsym(x11Context.pRandLibraryHandle, "XRRSetScreenSize");
     717    checkFunctionPtr(x11Context.pXRRSetScreenSize);
     718
     719    *(void **)(&x11Context.pXRRUpdateConfiguration) = dlsym(x11Context.pRandLibraryHandle, "XRRUpdateConfiguration");
     720    checkFunctionPtr(x11Context.pXRRUpdateConfiguration);
     721
     722    *(void **)(&x11Context.pXRRAllocModeInfo) = dlsym(x11Context.pRandLibraryHandle, "XRRUpdateConfiguration");
     723    checkFunctionPtr(x11Context.pXRRAllocModeInfo);
     724
     725    *(void **)(&x11Context.pXRRAllocModeInfo) = dlsym(x11Context.pRandLibraryHandle, "XRRUpdateConfiguration");
     726    checkFunctionPtr(x11Context.pXRRAllocModeInfo);
     727
     728    *(void **)(&x11Context.pXRRCreateMode) = dlsym(x11Context.pRandLibraryHandle, "XRRCreateMode");
     729    checkFunctionPtr(x11Context.pXRRCreateMode);
     730
     731    *(void **)(&x11Context.pXRRGetOutputInfo) = dlsym(x11Context.pRandLibraryHandle, "XRRGetOutputInfo");
     732    checkFunctionPtr(x11Context.pXRRGetOutputInfo);
     733
    435734    return VINF_SUCCESS;
    436735}
     
    439738static void x11Connect()
    440739{
     740    x11Context.pScreenResources = NULL;
    441741    x11Context.pXRRSelectInput = NULL;
    442742    x11Context.pRandLibraryHandle = NULL;
     
    444744    x11Context.pXRRQueryVersion = NULL;
    445745    x11Context.pXRRGetMonitors = NULL;
     746    x11Context.pXRRGetScreenResources = NULL;
     747    x11Context.pXRRSetCrtcConfig = NULL;
    446748    x11Context.pXRRFreeMonitors = NULL;
     749    x11Context.pXRRFreeScreenResources = NULL;
     750    x11Context.pXRRFreeOutputInfo = NULL;
     751    x11Context.pXRRFreeModeInfo = NULL;
     752    x11Context.pXRRSetScreenSize = NULL;
     753    x11Context.pXRRUpdateConfiguration = NULL;
     754    x11Context.pXRRAllocModeInfo = NULL;
     755    x11Context.pXRRCreateMode = NULL;
     756    x11Context.pXRRGetOutputInfo = NULL;
     757    x11Context.pXRRAddOutputMode = NULL;
    447758
    448759    int dummy;
     
    460771    }
    461772#endif
    462 
    463773    if (!XQueryExtension(x11Context.pDisplay, "VMWARE_CTRL",
    464774                         &x11Context.hVMWCtrlMajorOpCode, &dummy, &dummy))
     
    492802    }
    493803    x11Context.rootWindow = DefaultRootWindow(x11Context.pDisplay);
    494     x11Context.hOutputCount = determineOutputCount();
    495 
    496804    x11Context.hEventMask = RRScreenChangeNotifyMask;
    497805    if (x11Context.hRandRMinor >= 2)
     
    507815        x11Context.pXRRSelectInput(x11Context.pDisplay, x11Context.rootWindow, x11Context.hEventMask);
    508816#endif
    509 }
    510 
    511 /** run the xrandr command without options to get the total # of outputs (monitors) including
    512  *  disbaled ones. */
     817#ifdef WITH_DISTRO_XRAND_XINERAMA
     818    x11Context.pScreenResources = XRRGetScreenResources(x11Context.pDisplay, x11Context.rootWindow);
     819#else
     820    if (x11Context.pXRRGetScreenResources)
     821        x11Context.pScreenResources = x11Context.pXRRGetScreenResources(x11Context.pDisplay, x11Context.rootWindow);
     822#endif
     823    x11Context.iDefaultScreen = DefaultScreen(x11Context.pDisplay);
     824    x11Context.hOutputCount = determineOutputCount();
     825}
     826
    513827static int determineOutputCount()
    514828{
    515     int iCount = 0;
    516     char szCommand[MAX_COMMAND_LINE_LEN];
    517     RTStrPrintf(szCommand, sizeof(szCommand), "%s ", pcszXrandr);
    518 
    519     FILE *pFile;
    520     pFile = popen(szCommand, "r");
    521     if (pFile == NULL)
    522     {
    523         VBClLogError("Failed to run %s\n", szCommand);
    524         return VMW_MAX_HEADS;
    525     }
    526     char szModeLine[MAX_COMMAND_LINE_LEN];
    527     while (fgets(szModeLine, sizeof(szModeLine), pFile) != NULL)
    528     {
    529         if (RTStrIStr(szModeLine, szDefaultOutputNamePrefix))
    530             ++iCount;
    531     }
    532     if (iCount == 0)
    533         iCount = VMW_MAX_HEADS;
    534     return iCount;
    535 }
    536 
    537 /** Parse a single line of the output of xrandr command to extract Mode name.
    538  * Assumed to be null terminated and in following format:
    539  * e.g. 1016x559_vbox  59.70. where 1016x559_vbox is the mode name and at least one space in front
    540  * Set  mode name @p outPszModeName and return true if the name can be found, false otherwise.
    541  * outPszModeNameis assumed to be of length MAX_MODE_NAME_LEN. */
    542 static bool parseModeLine(char *pszLine, char *outPszModeName)
    543 {
    544     char *p = pszLine;
    545     (void*)outPszModeName;
    546     /* Copy chars to outPszModeName starting from the first non-space until outPszModeName ends with 'vbox'*/
    547     size_t iNameIndex = 0;
    548     bool fInitialSpace = true;
    549 
    550     while (*p)
    551     {
    552         if (*p != ' ')
    553             fInitialSpace = false;
    554         if (!fInitialSpace && iNameIndex < MAX_MODE_NAME_LEN)
     829    if (!x11Context.pScreenResources)
     830        return 0;
     831    return x11Context.pScreenResources->noutput;
     832}
     833
     834static int findExistingModeIndex(unsigned iXRes, unsigned iYRes)
     835{
     836    if (!x11Context.pScreenResources)
     837        return -1;
     838    for (int i = 0; i < x11Context.pScreenResources->nmode; ++i)
     839    {
     840        if (x11Context.pScreenResources->modes[i].width == iXRes && x11Context.pScreenResources->modes[i].height == iYRes)
     841            return i;
     842    }
     843    return -1;
     844}
     845
     846static bool disableCRTC(RRCrtc crtcID)
     847{
     848    Status ret;
     849#ifdef WITH_DISTRO_XRAND_XINERAMA
     850    ret = XRRSetCrtcConfig(x11Context.pDisplay, x11Context.pScreenResources, crtcID,
     851                           CurrentTime, 0, 0, None, RR_Rotate_0, NULL, 0);
     852#else
     853    if (x11Context.pXRRSetCrtcConfig)
     854        ret = x11Context.pXRRSetCrtcConfig(x11Context.pDisplay, x11Context.pScreenResources, crtcID,
     855                                           CurrentTime, 0, 0, None, RR_Rotate_0, NULL, 0);
     856#endif
     857    if (ret == Success)
     858        return false;
     859    else
     860    {
     861        VBClLogFatalError("Crtc disable failed %lu\n", crtcID);
     862        return false;
     863    }
     864}
     865
     866static XRRScreenSize currentSize()
     867{
     868    XRRScreenSize cSize;
     869    cSize.width = DisplayWidth(x11Context.pDisplay, x11Context.iDefaultScreen);
     870    cSize.mwidth = DisplayWidthMM(x11Context.pDisplay, x11Context.iDefaultScreen);
     871    cSize.height = DisplayHeight(x11Context.pDisplay, x11Context.iDefaultScreen);
     872    cSize.mheight = DisplayHeightMM(x11Context.pDisplay, x11Context.iDefaultScreen);
     873    return cSize;
     874}
     875
     876static unsigned int computeDpi(unsigned int pixels, unsigned int mm)
     877{
     878   unsigned int dpi = 0;
     879   if (mm > 0) {
     880      dpi = (unsigned int)((double)pixels * MILLIS_PER_INCH /
     881                           (double)mm + 0.5);
     882      printf("computed dpi %u\n", dpi);
     883   }
     884   return (dpi > 0) ? dpi : DEFAULT_DPI;
     885}
     886
     887static bool resizeFrameBuffer(struct RANDROUTPUT *paOutputs)
     888{
     889    unsigned int iXRes = 0;
     890    unsigned int iYRes = 0;
     891    /* Don't care about the output positions for now. */
     892    for (int i = 0; i < VMW_MAX_HEADS; ++i)
     893    {
     894        if (!paOutputs[i].fEnabled)
     895            continue;
     896        iXRes += paOutputs[i].width;
     897        iYRes = iYRes < paOutputs[i].height ? paOutputs[i].height : iYRes;
     898    }
     899    XRRScreenSize cSize= currentSize();
     900    unsigned int xdpi = computeDpi(cSize.width, cSize.mwidth);
     901    unsigned int ydpi = computeDpi(cSize.height, cSize.mheight);
     902    unsigned int xmm;
     903    unsigned int ymm;
     904    xmm = (int)(MILLIS_PER_INCH * iXRes / ((double)xdpi) + 0.5);
     905    ymm = (int)(MILLIS_PER_INCH * iYRes / ((double)ydpi) + 0.5);
     906#ifdef WITH_DISTRO_XRAND_XINERAMA
     907    XRRSelectInput(x11Context.pDisplay, x11Context.rootWindow, RRScreenChangeNotifyMask);
     908    XRRSetScreenSize(x11Context.pDisplay, x11Context.rootWindow, iXRes, iYRes, xmm, ymm);
     909#else
     910    if (x11Context.pXRRSelectInput)
     911        x11Context.pXRRSelectInput(x11Context.pDisplay, x11Context.rootWindow, RRScreenChangeNotifyMask);
     912    if (x11Context.pXRRSetScreenSize)
     913        x11Context.pXRRSetScreenSize(x11Context.pDisplay, x11Context.rootWindow, iXRes, iYRes, xmm, ymm);
     914#endif
     915    XSync(x11Context.pDisplay, False);
     916    XEvent configEvent;
     917    bool event = false;
     918    while (XCheckTypedEvent(x11Context.pDisplay, RRScreenChangeNotify + x11Context.hRandREventBase, &configEvent))
     919    {
     920#ifdef WITH_DISTRO_XRAND_XINERAMA
     921        XRRUpdateConfiguration(&configEvent);
     922#else
     923        if (x11Context.pXRRUpdateConfiguration)
     924            x11Context.pXRRUpdateConfiguration(&configEvent);
     925#endif
     926        event = true;
     927    }
     928#ifdef WITH_DISTRO_XRAND_XINERAMA
     929    XRRSelectInput(x11Context.pDisplay, x11Context.rootWindow, 0);
     930#else
     931    if (x11Context.pXRRSelectInput)
     932        x11Context.pXRRSelectInput(x11Context.pDisplay, x11Context.rootWindow, 0);
     933#endif
     934    XRRScreenSize newSize = currentSize();
     935    /** @todo  In case of unsuccesful frame buffer resize we have to revert frame buffer size and crtc sizes. */
     936    if (!event || newSize.width != (int)iXRes || newSize.height != (int)iYRes)
     937    {
     938        VBClLogError("Resizing frame buffer to %d %d has failed\n", iXRes, iYRes);
     939        return false;
     940    }
     941    return true;
     942}
     943
     944static XRRModeInfo *createMode(int iXRes, int iYRes)
     945{
     946    XRRModeInfo *pModeInfo = NULL;
     947    char sModeName[126];
     948    sprintf(sModeName, "%dx%d_vbox", iXRes, iYRes);
     949#ifdef WITH_DISTRO_XRAND_XINERAMA
     950    pModeInfo = XRRAllocModeInfo(sModeName, strlen(sModeName));
     951#else
     952    if (x11Context.pXRRAllocModeInfo)
     953        pModeInfo = x11Context.pXRRAllocModeInfo(sModeName, strlen(sModeName));
     954#endif
     955    pModeInfo->width = iXRes;
     956    pModeInfo->height = iYRes;
     957
     958    DisplayModeR mode = f86CVTMode(iXRes, iYRes, 60 /*VRefresh */, true /*Reduced */, false  /* Interlaced */);
     959
     960    pModeInfo->dotClock = mode.Clock;
     961    pModeInfo->hSyncStart = mode.HSyncStart;
     962    pModeInfo->hSyncEnd = mode.HSyncEnd;
     963    pModeInfo->hTotal = mode.HTotal;
     964    pModeInfo->hSkew = mode.HSkew;
     965    pModeInfo->vSyncStart = mode.VSyncStart;
     966    pModeInfo->vSyncEnd = mode.VSyncEnd;
     967    pModeInfo->vTotal = mode.VTotal;
     968
     969    RRMode newMode = None;
     970#ifdef WITH_DISTRO_XRAND_XINERAMA
     971    newMode = XRRCreateMode(x11Context.pDisplay, x11Context.rootWindow, pModeInfo);
     972#else
     973    if (x11Context.pXRRCreateMode)
     974        newMode = x11Context.pXRRCreateMode(x11Context.pDisplay, x11Context.rootWindow, pModeInfo);
     975#endif
     976    if (newMode == None)
     977    {
     978#ifdef WITH_DISTRO_XRAND_XINERAMA
     979        XRRFreeModeInfo(pModeInfo);
     980#else
     981        if (x11Context.pXRRFreeModeInfo)
     982            x11Context.pXRRFreeModeInfo(pModeInfo);
     983#endif
     984        return NULL;
     985    }
     986    pModeInfo->id = newMode;
     987    return pModeInfo;
     988}
     989
     990static bool configureOutput(int iOutputIndex, struct RANDROUTPUT *paOutputs)
     991{
     992    if (iOutputIndex >= x11Context.hOutputCount)
     993    {
     994        VBClLogError("Output index %d is greater than # of oputputs %d\n", iOutputIndex, x11Context.hOutputCount);
     995        return false;
     996    }
     997    RROutput outputId = x11Context.pScreenResources->outputs[iOutputIndex];
     998    XRROutputInfo *pOutputInfo = NULL;
     999#ifdef WITH_DISTRO_XRAND_XINERAMA
     1000    pOutputInfo = XRRGetOutputInfo(x11Context.pDisplay, x11Context.pScreenResources, outputId);
     1001#else
     1002    if (x11Context.pXRRGetOutputInfo)
     1003        pOutputInfo = x11Context.pXRRGetOutputInfo(x11Context.pDisplay, x11Context.pScreenResources, outputId);
     1004#endif
     1005
     1006    XRRModeInfo *pModeInfo = NULL;
     1007    bool fNewMode = false;
     1008    /* Index of the mode within the XRRScreenResources.modes array. -1 if such a mode with required resolution does not exists*/
     1009    int iModeIndex = findExistingModeIndex(paOutputs[iOutputIndex].width, paOutputs[iOutputIndex].height);
     1010    if (iModeIndex != -1 && iModeIndex < x11Context.hOutputCount)
     1011        pModeInfo = &(x11Context.pScreenResources->modes[iModeIndex]);
     1012    else
     1013    {
     1014        /* A mode with required size was not found. Create a new one. */
     1015        pModeInfo = createMode(paOutputs[iOutputIndex].width, paOutputs[iOutputIndex].height);
     1016        fNewMode = true;
     1017    }
     1018    if (!pModeInfo)
     1019    {
     1020        VBClLogError("Could not create mode for the resolution (%d, %d)\n",
     1021                     paOutputs[iOutputIndex].width, paOutputs[iOutputIndex].height);
     1022        return false;
     1023    }
     1024
     1025#ifdef WITH_DISTRO_XRAND_XINERAMA
     1026    XRRAddOutputMode(x11Context.pDisplay, outputId, pModeInfo->id);
     1027#else
     1028    if (x11Context.pXRRAddOutputMode)
     1029        x11Context.pXRRAddOutputMode(x11Context.pDisplay, outputId, pModeInfo->id);
     1030#endif
     1031    /* Make sure outputs crtc is set. */
     1032    pOutputInfo->crtc = pOutputInfo->crtcs[0];
     1033
     1034    RRCrtc crtcId = pOutputInfo->crtcs[0];
     1035    Status ret;
     1036#ifdef WITH_DISTRO_XRAND_XINERAMA
     1037    ret = XRRSetCrtcConfig(x11Context.pDisplay, x11Context.pScreenResources, crtcId, CurrentTime,
     1038                           paOutputs[iOutputIndex].x, paOutputs[iOutputIndex].y,
     1039                           pModeInfo->id, RR_Rotate_0, &(outputId), 1 /*int noutputs*/);
     1040#else
     1041    if (x11Context.pXRRSetCrtcConfig)
     1042        ret = x11Context.pXRRSetCrtcConfig(x11Context.pDisplay, x11Context.pScreenResources, crtcId, CurrentTime,
     1043                                           paOutputs[iOutputIndex].x, paOutputs[iOutputIndex].y,
     1044                                           pModeInfo->id, RR_Rotate_0, &(outputId), 1 /*int noutputs*/);
     1045#endif
     1046    if (ret != Success)
     1047        VBClLogError("crtc set config failed for output %d\n", iOutputIndex);
     1048
     1049#ifdef WITH_DISTRO_XRAND_XINERAMA
     1050    XRRFreeOutputInfo(pOutputInfo);
     1051#else
     1052    if (x11Context.pXRRFreeOutputInfo)
     1053        x11Context.pXRRFreeOutputInfo(pOutputInfo);
     1054#endif
     1055
     1056    if (fNewMode)
     1057    {
     1058#ifdef WITH_DISTRO_XRAND_XINERAMA
     1059        XRRFreeModeInfo(pModeInfo);
     1060#else
     1061        if (x11Context.pXRRFreeModeInfo)
     1062            x11Context.pXRRFreeModeInfo(pModeInfo);
     1063#endif
     1064    }
     1065    return true;
     1066}
     1067
     1068/** Construct the xrandr command which sets the whole monitor topology each time. */
     1069static void setXrandrTopology(struct RANDROUTPUT *paOutputs)
     1070{
     1071    XGrabServer(x11Context.pDisplay);
     1072    (void*)paOutputs;
     1073    if (!x11Context.pScreenResources)
     1074        return;
     1075    /* Disable all crtcs. */
     1076    for (int i = 0; i , x11Context.pScreenResources->ncrtc; ++i)
     1077    {
     1078        if (!disableCRTC(x11Context.pScreenResources->crtcs[i]))
    5551079        {
    556             outPszModeName[iNameIndex] = *p;
    557             ++iNameIndex;
    558             if (iNameIndex >= 4)
    559             {
    560                 if (   outPszModeName[iNameIndex-1] == 'x'
    561                     && outPszModeName[iNameIndex-2] == 'o'
    562                     && outPszModeName[iNameIndex-3] == 'b')
    563                     break;
    564             }
     1080            XUngrabServer(x11Context.pDisplay);
     1081            return;
    5651082        }
    566         ++p;
    567     }
    568     outPszModeName[iNameIndex] = '\0';
    569     return true;
    570 }
    571 
    572 /** Parse the output of the xrandr command to try to remove custom modes.
    573  * This function assumes all the outputs are named as VirtualX. */
    574 static void removeCustomModesFromOutputs()
    575 {
    576     char szCommand[MAX_COMMAND_LINE_LEN];
    577     RTStrPrintf(szCommand, sizeof(szCommand), "%s ", pcszXrandr);
    578 
    579     FILE *pFile;
    580     pFile = popen(szCommand, "r");
    581     if (pFile == NULL)
    582     {
    583         VBClLogError("Failed to run %s\n", szCommand);
    584         return;
    585     }
    586     char szModeLine[MAX_COMMAND_LINE_LEN];
    587     char szModeName[MAX_MODE_NAME_LEN];
    588     int iCount = 0;
    589     char szRmModeCommand[MAX_COMMAND_LINE_LEN];
    590     char szDelModeCommand[MAX_COMMAND_LINE_LEN];
    591 
    592     while (fgets(szModeLine, sizeof(szModeLine), pFile) != NULL)
    593     {
    594         if (RTStrIStr(szModeLine, szDefaultOutputNamePrefix))
    595         {
    596             ++iCount;
     1083    }
     1084    /* Resize the frame buffer. */
     1085    resizeFrameBuffer(paOutputs);
     1086
     1087    /* Configure the outputs. */
     1088    for (int i = 0; i < x11Context.hOutputCount; ++i)
     1089    {
     1090        /* be paranoid. */
     1091        if (i >= x11Context.pScreenResources->noutput)
     1092            break;
     1093        if (!paOutputs[i].fEnabled)
    5971094            continue;
    598         }
    599         if (iCount > 0 && RTStrIStr(szModeLine, "_vbox"))
    600         {
    601             parseModeLine(szModeLine, szModeName);
    602             if (strlen(szModeName) >= 4)
    603             {
    604                 /* Delete the mode from the outout. this fails if the mode is currently in use. */
    605                 RTStrPrintf(szDelModeCommand, sizeof(szDelModeCommand), "%s --delmode Virtual%d %s", pcszXrandr, iCount, szModeName);
    606                 system(szDelModeCommand);
    607                 /* Delete the mode from the xserver. note that this will fail if some output has still has this mode (even if unused).
    608                  * thus this will fail most of the time. */
    609                 RTStrPrintf(szRmModeCommand, sizeof(szRmModeCommand), "%s --rmmode %s", pcszXrandr, szModeName);
    610                 system(szRmModeCommand);
    611             }
    612         }
    613     }
    614 }
    615 
    616 static void getModeNameAndLineFromCVT(int iWidth, int iHeight, char *pszOutModeName, char *pszOutModeLine)
    617 {
    618     char szCvtCommand[MAX_COMMAND_LINE_LEN];
    619     const int iFreq = 60;
    620     const int iMinNameLen = 4;
    621     /* Make release builds happy. */
    622     (void)iMinNameLen;
    623     RTStrPrintf(szCvtCommand, sizeof(szCvtCommand), "%s %d %d %d", pcszCvt, iWidth, iHeight, iFreq);
    624     FILE *pFile;
    625     pFile = popen(szCvtCommand, "r");
    626     if (pFile == NULL)
    627     {
    628         VBClLogError("Failed to run %s\n", szCvtCommand);
    629         return;
    630     }
    631 
    632     char szModeLine[MAX_COMMAND_LINE_LEN];
    633     while (fgets(szModeLine, sizeof(szModeLine), pFile) != NULL)
    634     {
    635         if (RTStrStr(szModeLine, "Modeline"))
    636         {
    637             if(szModeLine[strlen(szModeLine) - 1] == '\n')
    638                 szModeLine[strlen(szModeLine) - 1] = '\0';
    639             size_t iFirstQu = RTStrOffCharOrTerm(szModeLine, '\"');
    640             size_t iModeLineLen = strlen(szModeLine);
    641             /* Make release builds happy. */
    642             (void)iModeLineLen;
    643             Assert(iFirstQu < iModeLineLen - iMinNameLen);
    644 
    645             char *p = &(szModeLine[iFirstQu + 1]);
    646             size_t iSecondQu = RTStrOffCharOrTerm(p, '_');
    647             Assert(iSecondQu > iMinNameLen);
    648             Assert(iSecondQu < MAX_MODE_NAME_LEN);
    649             Assert(iSecondQu < iModeLineLen);
    650 
    651             RTStrCopy(pszOutModeName, iSecondQu + 2, p);
    652             RTStrCat(pszOutModeName, MAX_MODE_NAME_LEN, "vbox");
    653             iSecondQu = RTStrOffCharOrTerm(p, '\"');
    654             RTStrCopy(pszOutModeLine, MAX_MODE_LINE_LEN, &(szModeLine[iFirstQu + iSecondQu + 2]));
    655             break;
    656         }
    657     }
    658 }
    659 
    660 /** Add a new mode to xserver and to the output */
    661 static void addMode(const char *pszModeName, const char *pszModeLine)
    662 {
    663     char szNewModeCommand[MAX_COMMAND_LINE_LEN];
    664     RTStrPrintf(szNewModeCommand, sizeof(szNewModeCommand), "%s --newmode \"%s\" %s", pcszXrandr, pszModeName, pszModeLine);
    665     system(szNewModeCommand);
    666 
    667     char szAddModeCommand[1024];
    668     /* try to add the new mode to all possible outputs. we currently dont care if most the are disabled. */
    669     for(int i = 0; i < x11Context.hOutputCount; ++i)
    670     {
    671         RTStrPrintf(szAddModeCommand, sizeof(szAddModeCommand), "%s --addmode Virtual%d \"%s\"", pcszXrandr, i + 1, pszModeName);
    672         system(szAddModeCommand);
    673     }
    674 }
    675 
    676 static bool checkDefaultModes(struct RANDROUTPUT *pOutput, int iOutputIndex, char *pszModeName)
    677 {
    678     const char szError[] = "cannot find mode";
    679     char szXranrCommand[MAX_COMMAND_LINE_LEN];
    680     RTStrPrintf(szXranrCommand, sizeof(szXranrCommand),
    681                 "%s --dryrun --output Virtual%u --mode %dx%d --pos %dx%d 2>/dev/stdout", pcszXrandr, iOutputIndex,
    682                 pOutput->width, pOutput->height, pOutput->x, pOutput->y);
    683     RTStrPrintf(pszModeName, MAX_MODE_NAME_LEN, "%dx%d", pOutput->width, pOutput->height);
    684     FILE *pFile;
    685     pFile = popen(szXranrCommand, "r");
    686     if (pFile == NULL)
    687     {
    688         VBClLogError("Failed to run %s\n", szXranrCommand);
    689         return false;
    690     }
    691     char szResult[64];
    692     if (fgets(szResult, sizeof(szResult), pFile) != NULL)
    693     {
    694         if (RTStrIStr(szResult, szError))
    695             return false;
    696     }
    697     return true;
    698 }
    699 
    700 /** Construct the xrandr command which sets the whole monitor topology each time. */
    701 static void setXrandrModes(struct RANDROUTPUT *paOutputs)
    702 {
    703     char szCommand[MAX_COMMAND_LINE_LEN];
    704     RTStrPrintf(szCommand, sizeof(szCommand), "%s ", pcszXrandr);
    705 
    706     for (int i = 0; i < x11Context.hOutputCount; ++i)
    707     {
    708         char line[64];
    709         if (!paOutputs[i].fEnabled)
    710             RTStrPrintf(line, sizeof(line), "--output Virtual%u --off ", i + 1);
    711         else
    712         {
    713             char szModeName[MAX_MODE_NAME_LEN];
    714             char szModeLine[MAX_MODE_LINE_LEN];
    715             /* Check if there is a default mode for the widthxheight and if not create and add a custom mode. */
    716             if (!checkDefaultModes(&(paOutputs[i]), i + 1, szModeName))
    717             {
    718                 getModeNameAndLineFromCVT(paOutputs[i].width, paOutputs[i].height, szModeName, szModeLine);
    719                 addMode(szModeName, szModeLine);
    720             }
    721             else
    722                 RTStrPrintf(szModeName, sizeof(szModeName), "%dx%d ", paOutputs[i].width, paOutputs[i].height);
    723 
    724             RTStrPrintf(line, sizeof(line), "--output Virtual%u --mode %s --pos %dx%d ", i + 1,
    725                         szModeName, paOutputs[i].x, paOutputs[i].y);
    726         }
    727         RTStrCat(szCommand, sizeof(szCommand), line);
    728     }
    729     system(szCommand);
    730     VBClLogInfo("=======xrandr topology command:=====\n%s\n", szCommand);
    731     removeCustomModesFromOutputs();
     1095        configureOutput(i, paOutputs);
     1096    }
     1097    XUngrabServer(x11Context.pDisplay);
    7321098}
    7331099
     
    8111177                    iRunningX += aOutputs[j].width;
    8121178            }
    813             setXrandrModes(aOutputs);
     1179            setXrandrTopology(aOutputs);
    8141180        }
    8151181        do
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