status_t VBoxDisplayService::_ServiceThread() { LogFlow(("VBoxDisplayService::_ServiceThread")); VbglR3CtlFilterMask(VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST, 0); VbglR3SetGuestCaps(VMMDEV_GUEST_SUPPORTS_GRAPHICS, 0); for (;;) { uint32_t events; int rc = VbglR3WaitEvent(VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST, 5000, &events); if (rc == -6) // timed out? continue; if (RT_SUCCESS(rc)) { uint32_t cx, cy, cBits, iDisplay; int rc2 = VbglR3GetDisplayChangeRequest(&cx, &cy, &cBits, &iDisplay, true); LogFlow(("rc2=%d screen %d size changed (%d, %d, %d)\n", rc2, iDisplay, cx, cy, cBits)); if (RT_SUCCESS(rc2)) { display_mode mode; fScreen.GetMode(&mode); if (cBits == 0) cBits = get_depth_for_color_space(mode.space); mode.timing.h_display = cx; mode.timing.v_display = cy; mode.space = get_color_space_for_depth(cBits); mode.virtual_width = cx; mode.virtual_height = cy; /*= { {0, cx, 0, 0, cBits * cx / 8, cy, 0, 0, cBits * cy / 8, 0}, get_color_space_for_depth(cBits), cx, cy, 0, 0, 0 };*/ fScreen.SetMode(&mode, false); } } else fExiting = true; LogFlow(("processed host event rc = %d\n", rc)); if (fExiting) break; } return 0; }
/** * Query the last display change request. * * @returns boolean success indicator. * @param pScrn Pointer to the X screen info structure. * @param pcx Where to store the horizontal pixel resolution (0 = do not change). * @param pcy Where to store the vertical pixel resolution (0 = do not change). * @param pcBits Where to store the bits per pixel (0 = do not change). * @param iDisplay Where to store the display number the request was for - 0 for the * primary display, 1 for the first secondary, etc. */ Bool vboxGetDisplayChangeRequest(ScrnInfoPtr pScrn, uint32_t *pcx, uint32_t *pcy, uint32_t *pcBits, uint32_t *piDisplay) { VBOXPtr pVBox = pScrn->driverPrivate; TRACE_ENTRY(); if (!pVBox->useDevice) return FALSE; int rc = VbglR3GetDisplayChangeRequest(pcx, pcy, pcBits, piDisplay, false); if (RT_SUCCESS(rc)) return TRUE; xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to obtain the last resolution requested by the guest, rc=%d.\n", rc); return FALSE; }
/** * Display change request monitor thread function. * Before entering the loop, we re-read the last request * received, and if the first one received inside the * loop is identical we ignore it, because it is probably * stale. */ static int runDisplay(Display *pDisplay) { LogRelFlowFunc(("\n")); Cursor hClockCursor = XCreateFontCursor(pDisplay, XC_watch); Cursor hArrowCursor = XCreateFontCursor(pDisplay, XC_left_ptr); int RRMaj, RRMin; if (!XRRQueryVersion(pDisplay, &RRMaj, &RRMin)) RRMin = 0; const char *pcszXrandr = "xrandr"; if (RTFileExists("/usr/X11/bin/xrandr")) pcszXrandr = "/usr/X11/bin/xrandr"; int rc = RTThreadCreate(NULL, x11ConnectionMonitor, NULL, 0, RTTHREADTYPE_INFREQUENT_POLLER, 0, "X11 monitor"); if (RT_FAILURE(rc)) return rc; while (true) { uint32_t fEvents = 0, cx = 0, cy = 0, cBits = 0, iDisplay = 0; rc = VbglR3WaitEvent( VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST | VMMDEV_EVENT_MOUSE_CAPABILITIES_CHANGED, RT_INDEFINITE_WAIT, &fEvents); if (RT_FAILURE(rc) && rc != VERR_INTERRUPTED) /* VERR_NO_MEMORY? */ return rc; /* Jiggle the mouse pointer to wake up the driver. */ XGrabPointer(pDisplay, DefaultRootWindow(pDisplay), true, 0, GrabModeAsync, GrabModeAsync, None, hClockCursor, CurrentTime); XFlush(pDisplay); XGrabPointer(pDisplay, DefaultRootWindow(pDisplay), true, 0, GrabModeAsync, GrabModeAsync, None, hArrowCursor, CurrentTime); XFlush(pDisplay); XUngrabPointer(pDisplay, CurrentTime); XFlush(pDisplay); /* And if it is a size hint, set the new size now that the video * driver has had a chance to update its list. */ if (RT_SUCCESS(rc) && (fEvents & VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST)) { int rc2 = VbglR3GetDisplayChangeRequest(&cx, &cy, &cBits, &iDisplay, true); /* If we are not stopping, sleep for a bit to avoid using up too much CPU while retrying. */ if (RT_FAILURE(rc2)) RTThreadYield(); else if (RRMin < 2) setSize(pDisplay, cx, cy); else { char szCommand[256]; RTStrPrintf(szCommand, sizeof(szCommand), "%s --output VBOX%u --set VBOX_MODE %dx%d", pcszXrandr, iDisplay, cx, cy); system(szCommand); RTStrPrintf(szCommand, sizeof(szCommand), "%s --output VBOX%u --preferred", pcszXrandr, iDisplay); system(szCommand); } } } LogRelFlowFunc(("returning VINF_SUCCESS\n")); return VINF_SUCCESS; }