Changeset 83910 in vbox for trunk/src/VBox/Additions/x11
- Timestamp:
- Apr 21, 2020 7:31:41 PM (5 years ago)
- svn:sync-xref-src-repo-rev:
- 137447
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Additions/x11/VBoxClient/display-svga-x11.cpp
r83257 r83910 36 36 * screen, and enabling others should not be possible. 37 37 * - 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. 38 41 */ 39 42 #include <stdio.h> … … 53 56 #include <X11/extensions/Xrandr.h> 54 57 #include <X11/extensions/panoramiXproto.h> 58 59 #define MILLIS_PER_INCH (25.4) 60 #define DEFAULT_DPI (96.0) 61 55 62 56 63 /** Maximum number of supported screens. DRM and X11 both limit this to 32. */ … … 104 111 { 105 112 Display *pDisplay; 113 Window rootWindow; 114 int iDefaultScreen; 115 XRRScreenResources *pScreenResources; 106 116 int hRandRMajor; 107 117 int hVMWCtrlMajorOpCode; … … 112 122 /** The number of outputs (monitors, including disconnect ones) xrandr reports. */ 113 123 int hOutputCount; 114 Window rootWindow;115 124 void *pRandLibraryHandle; 125 /** Function pointers we used if we dlopen libXrandr instead of linking. */ 116 126 void (*pXRRSelectInput) (Display *, Window, int); 117 127 Bool (*pXRRQueryExtension) (Display *, int *, int *); 118 128 Status (*pXRRQueryVersion) (Display *, int *, int*); 119 129 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); 120 133 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); 121 143 }; 122 144 … … 126 148 #define MAX_COMMAND_LINE_LEN 512 127 149 #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";132 150 133 151 struct RANDROUTPUT … … 138 156 uint32_t height; 139 157 bool fEnabled; 158 }; 159 160 struct 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; 140 176 }; 141 177 … … 154 190 } \ 155 191 }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. */ 198 DisplayModeR 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 156 418 157 419 bool VMwareCtrlSetTopology(Display *dpy, int hExtensionMajorOpcode, … … 312 574 static int startX11MonitorThread() 313 575 { 576 return 0; 314 577 int rc; 315 578 … … 396 659 #ifdef WITH_DISTRO_XRAND_XINERAMA 397 660 XRRSelectInput(x11Context.pDisplay, x11Context.rootWindow, 0); 661 XRRFreeScreenResources(x11Context.pScreenResources); 398 662 #else 399 663 if (x11Context.pXRRSelectInput) 400 664 x11Context.pXRRSelectInput(x11Context.pDisplay, x11Context.rootWindow, 0); 665 if (x11Context.pXRRFreeScreenResources) 666 x11Context.pXRRFreeScreenResources(x11Context.pScreenResources); 401 667 #endif 402 668 XCloseDisplay(x11Context.pDisplay); … … 430 696 checkFunctionPtr(x11Context.pXRRGetMonitors); 431 697 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 432 704 *(void **)(&x11Context.pXRRFreeMonitors) = dlsym(x11Context.pRandLibraryHandle, "XRRFreeMonitors"); 433 705 checkFunctionPtr(x11Context.pXRRFreeMonitors); 434 706 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 435 734 return VINF_SUCCESS; 436 735 } … … 439 738 static void x11Connect() 440 739 { 740 x11Context.pScreenResources = NULL; 441 741 x11Context.pXRRSelectInput = NULL; 442 742 x11Context.pRandLibraryHandle = NULL; … … 444 744 x11Context.pXRRQueryVersion = NULL; 445 745 x11Context.pXRRGetMonitors = NULL; 746 x11Context.pXRRGetScreenResources = NULL; 747 x11Context.pXRRSetCrtcConfig = NULL; 446 748 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; 447 758 448 759 int dummy; … … 460 771 } 461 772 #endif 462 463 773 if (!XQueryExtension(x11Context.pDisplay, "VMWARE_CTRL", 464 774 &x11Context.hVMWCtrlMajorOpCode, &dummy, &dummy)) … … 492 802 } 493 803 x11Context.rootWindow = DefaultRootWindow(x11Context.pDisplay); 494 x11Context.hOutputCount = determineOutputCount();495 496 804 x11Context.hEventMask = RRScreenChangeNotifyMask; 497 805 if (x11Context.hRandRMinor >= 2) … … 507 815 x11Context.pXRRSelectInput(x11Context.pDisplay, x11Context.rootWindow, x11Context.hEventMask); 508 816 #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 513 827 static int determineOutputCount() 514 828 { 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 834 static 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 846 static 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 866 static 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 876 static 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 887 static 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 944 static 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 990 static 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. */ 1069 static 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])) 555 1079 { 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; 565 1082 } 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) 597 1094 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); 732 1098 } 733 1099 … … 811 1177 iRunningX += aOutputs[j].width; 812 1178 } 813 setXrandr Modes(aOutputs);1179 setXrandrTopology(aOutputs); 814 1180 } 815 1181 do
Note:
See TracChangeset
for help on using the changeset viewer.