Changeset 51243 in vbox
- Timestamp:
- May 13, 2014 2:16:56 PM (11 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Additions/x11/VBoxClient/display.cpp
r50432 r51243 24 24 25 25 #include <X11/Xlib.h> 26 #include <X11/Xatom.h> 26 27 #include <X11/cursorfont.h> 27 #include <X11/extensions/Xrandr.h>28 28 29 29 #include <iprt/assert.h> 30 30 #include <iprt/err.h> 31 31 #include <iprt/file.h> 32 #include <iprt/mem.h> 32 33 #include <iprt/string.h> 33 34 #include <iprt/thread.h> … … 38 39 #include "VBoxClient.h" 39 40 41 /** Exit with a fatal error. 42 * @todo Make this application global. */ 43 #define FatalError(format) \ 44 do { \ 45 char *pszMessage = RTStrAPrintf2 format; \ 46 LogRel(format); \ 47 doFatalError(pszMessage); \ 48 } while(0) 49 50 static void doFatalError(char *pszMessage) 51 { 52 char *pszCommand; 53 if (pszMessage) 54 { 55 pszCommand = RTStrAPrintf2("notify-send \"VBoxClient: %s\"", 56 pszMessage); 57 if (pszCommand) 58 system(pszCommand); 59 } 60 exit(1); 61 } 62 40 63 /** Tell the VBoxGuest driver we no longer want any events and tell the host 41 64 * we no longer support any capabilities. */ 42 65 static int disableEventsAndCaps() 43 66 { 44 int rc, rc2; 45 rc = VbglR3SetGuestCaps(0, VMMDEV_GUEST_SUPPORTS_GRAPHICS); 46 rc2 = VbglR3SetMouseStatus(VMMDEV_MOUSE_GUEST_NEEDS_HOST_CURSOR); 47 rc = RT_FAILURE(rc) ? rc : rc2; 48 rc2 = VbglR3CtlFilterMask(0, VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST); 49 rc = RT_FAILURE(rc) ? rc : rc2; 50 return rc; 67 int rc = VbglR3SetGuestCaps(0, VMMDEV_GUEST_SUPPORTS_GRAPHICS); 68 if (RT_FAILURE(rc)) 69 FatalError(("Failed to unset graphics capability, rc=%Rrc.\n", rc)); 70 rc = VbglR3SetMouseStatus(VMMDEV_MOUSE_GUEST_NEEDS_HOST_CURSOR); 71 if (RT_FAILURE(rc)) 72 FatalError(("Failed to unset mouse status, rc=%Rrc.\n", rc)); 73 rc = VbglR3CtlFilterMask(0, VMMDEV_EVENT_MOUSE_CAPABILITIES_CHANGED 74 | VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST); 75 if (RT_FAILURE(rc)) 76 FatalError(("Failed to unset filter mask, rc=%Rrc.\n", rc)); 77 return VINF_SUCCESS; 51 78 } 52 79 53 80 /** Tell the VBoxGuest driver which events we want and tell the host which 54 81 * capabilities we support. */ 55 static int enableEventsAndCaps(Display *pDisplay, bool fFirstTime) 56 { 57 int iDummy, rc; 58 uint32_t fFilterMask = VMMDEV_EVENT_MOUSE_CAPABILITIES_CHANGED; 59 uint32_t fCapabilities = 0; 60 if (XRRQueryExtension(pDisplay, &iDummy, &iDummy)) 61 { 62 fFilterMask |= VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST; 63 fCapabilities |= VMMDEV_GUEST_SUPPORTS_GRAPHICS; 64 } 65 else if (fFirstTime) 66 LogRel(("VBoxClient: guest does not support dynamic resizing.\n")); 67 rc = VbglR3CtlFilterMask(VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST, 0); 68 if (RT_SUCCESS(rc)) 69 rc = VbglR3SetGuestCaps(VMMDEV_GUEST_SUPPORTS_GRAPHICS, 0); 70 /** @todo Make sure that VBoxGuest understands 71 * VMMDEV_MOUSE_GUEST_NEEDS_HOST_CURSOR as a "negative" capability: if we 72 * don't advertise it it means we *can* switch to a software cursor and 73 * back. */ 74 if (RT_SUCCESS(rc)) 75 rc = VbglR3SetMouseStatus(0); 76 if (RT_FAILURE(rc)) 77 disableEventsAndCaps(); 78 return rc; 79 } 80 81 /** 82 * This method first resets the current resolution using RandR to wake up 83 * the graphics driver, then sets the resolution requested if it is among 84 * those offered by the driver. 85 */ 86 static void setSize(Display *pDisplay, uint32_t cx, uint32_t cy) 87 { 88 XRRScreenConfiguration *pConfig; 89 XRRScreenSize *pSizes; 90 int cSizes; 91 pConfig = XRRGetScreenInfo(pDisplay, DefaultRootWindow(pDisplay)); 92 /* Reset the current mode */ 93 LogRelFlowFunc(("Setting size %ux%u\n", cx, cy)); 94 if (pConfig) 95 { 96 pSizes = XRRConfigSizes(pConfig, &cSizes); 97 unsigned uDist = UINT32_MAX; 98 int iMode = -1; 99 for (int i = 0; i < cSizes; ++i) 100 { 101 #define VBCL_SQUARE(x) (x) * (x) 102 unsigned uThisDist = VBCL_SQUARE(pSizes[i].width - cx) 103 + VBCL_SQUARE(pSizes[i].height - cy); 104 LogRelFlowFunc(("Found size %dx%d, distance %u\n", pSizes[i].width, 105 pSizes[i].height, uThisDist)); 106 #undef VBCL_SQUARE 107 if (uThisDist < uDist) 108 { 109 uDist = uThisDist; 110 iMode = i; 111 } 112 } 113 if (iMode >= 0) 114 { 115 Time config_timestamp = 0; 116 XRRConfigTimes(pConfig, &config_timestamp); 117 LogRelFlowFunc(("Setting new size %d\n", iMode)); 118 XRRSetScreenConfig(pDisplay, pConfig, 119 DefaultRootWindow(pDisplay), iMode, 120 RR_Rotate_0, config_timestamp); 121 } 122 XRRFreeScreenConfigInfo(pConfig); 123 } 82 static int enableEventsAndCaps(Display *pDisplay) 83 { 84 int rc = VbglR3CtlFilterMask( VMMDEV_EVENT_MOUSE_CAPABILITIES_CHANGED 85 | VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST, 0); 86 if (RT_FAILURE(rc)) 87 FatalError(("Failed to set filter mask, rc=%Rrc.\n", rc)); 88 rc = VbglR3SetGuestCaps(VMMDEV_GUEST_SUPPORTS_GRAPHICS, 0); 89 if (RT_FAILURE(rc)) 90 FatalError(("Failed to set graphics capability, rc=%Rrc.\n", rc)); 91 rc = VbglR3SetMouseStatus(0); 92 if (RT_FAILURE(rc)) 93 FatalError(("Failed to set mouse status, rc=%Rrc.\n", rc)); 94 return VINF_SUCCESS; 124 95 } 125 96 … … 133 104 static void runDisplay(Display *pDisplay) 134 105 { 135 LogRelFlowFunc(("\n")); 106 int status, rc; 107 char szCommand[256]; 136 108 Cursor hClockCursor = XCreateFontCursor(pDisplay, XC_watch); 137 109 Cursor hArrowCursor = XCreateFontCursor(pDisplay, XC_left_ptr); 138 int RRMaj, RRMin; 139 bool fExtDispReqSupport = true; 140 if (!XRRQueryVersion(pDisplay, &RRMaj, &RRMin)) 141 RRMin = 0; 110 LogRelFlowFunc(("\n")); 111 bool fExtDispReqSupport = true, fHaveRandR12 = false; 142 112 const char *pcszXrandr = "xrandr"; 143 113 if (RTFileExists("/usr/X11/bin/xrandr")) 144 114 pcszXrandr = "/usr/X11/bin/xrandr"; 115 status = system(pcszXrandr); 116 if (WEXITSTATUS(status) != 0) /* Utility or extension not available. */ 117 FatalError(("Failed to execute the xrandr utility.\n")); 118 RTStrPrintf(szCommand, sizeof(szCommand), "%s --q12", pcszXrandr); 119 status = system(szCommand); 120 if (WEXITSTATUS(status) == 0) 121 fHaveRandR12 = true; 145 122 while (true) 146 123 { 147 uint32_t fEvents = 0, cx = 0, cy = 0, cBits = 0, iDisplay = 0, cxOrg = 0, cyOrg = 0; 148 bool fEnabled = false; 149 int rc = VbglR3WaitEvent( VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST 124 uint32_t fEvents; 125 /** The size of our array of size hints. */ 126 unsigned cSizeHints = 0; 127 /** Array of size hints. Large enough to hold the highest display 128 * number we have had a hint for so far, reallocated when a higher one 129 * comes. Zero means no hint for that display. */ 130 long *paSizeHints = NULL; 131 do 132 rc = VbglR3WaitEvent( VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST 150 133 | VMMDEV_EVENT_MOUSE_CAPABILITIES_CHANGED, 151 134 RT_INDEFINITE_WAIT, &fEvents); 152 if (RT_FAILURE(rc) && rc != VERR_INTERRUPTED) /* VERR_NO_MEMORY? */ 135 while(rc == VERR_INTERRUPTED); 136 if (RT_FAILURE(rc)) /* VERR_NO_MEMORY? */ 137 FatalError(("event wait failed, rc=%Rrc\n", rc)); 138 if (fEvents & VMMDEV_EVENT_MOUSE_CAPABILITIES_CHANGED) 153 139 { 154 LogRelFunc(("VBoxClient: VbglR3WaitEvent failed, rc=%Rrc\n", rc)); 155 VBoxClient::CleanUp(); 140 /* Jiggle the mouse pointer to trigger a switch to a software 141 * cursor if necessary. */ 142 XGrabPointer(pDisplay, 143 DefaultRootWindow(pDisplay), true, 0, GrabModeAsync, 144 GrabModeAsync, None, hClockCursor, CurrentTime); 145 XFlush(pDisplay); 146 XGrabPointer(pDisplay, 147 DefaultRootWindow(pDisplay), true, 0, GrabModeAsync, 148 GrabModeAsync, None, hArrowCursor, CurrentTime); 149 XFlush(pDisplay); 150 XUngrabPointer(pDisplay, CurrentTime); 151 XFlush(pDisplay); 156 152 } 157 /* Jiggle the mouse pointer to wake up the driver. */ 158 XGrabPointer(pDisplay, 159 DefaultRootWindow(pDisplay), true, 0, GrabModeAsync, 160 GrabModeAsync, None, hClockCursor, CurrentTime); 161 XFlush(pDisplay); 162 XGrabPointer(pDisplay, 163 DefaultRootWindow(pDisplay), true, 0, GrabModeAsync, 164 GrabModeAsync, None, hArrowCursor, CurrentTime); 165 XFlush(pDisplay); 166 XUngrabPointer(pDisplay, CurrentTime); 167 XFlush(pDisplay); 168 /* And if it is a size hint, set the new size now that the video 169 * driver has had a chance to update its list. */ 170 if (RT_SUCCESS(rc) && (fEvents & VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST)) 153 /* And if it is a size hint, set the new size. */ 154 if (fEvents & VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST) 171 155 { 172 int rc2 = VbglR3GetDisplayChangeRequestEx(&cx, &cy, &cBits, 173 &iDisplay, &cxOrg, &cyOrg, &fEnabled, true); 174 /* Extended display version not supported on host */ 175 if (RT_FAILURE(rc2)) 176 { 177 LogRel(("GetDisplayChangeReq Extended Version not supported. " 178 "Trying for Normal Mode with cx=%d & cy=%d\n", cx, cy)); 179 fExtDispReqSupport = false; 180 rc2 = VbglR3GetDisplayChangeRequest(&cx, &cy, &cBits, &iDisplay, true); 156 uint32_t cx = 0, cy = 0, cBits = 0, iDisplay = 0, cxOrg = 0, 157 cyOrg = 0; 158 bool fEnabled = false; 159 if (fExtDispReqSupport) 160 { 161 int rc2 = VbglR3GetDisplayChangeRequestEx(&cx, &cy, &cBits, 162 &iDisplay, &cxOrg, 163 &cyOrg, &fEnabled, 164 true); 165 /* Extended display version not supported on host */ 166 if (RT_FAILURE(rc2)) 167 { 168 if (rc2 != VERR_NOT_IMPLEMENTED) 169 FatalError(("Failed to get display change request, rc=%Rrc\n", 170 rc)); 171 LogRel(("Extended display change request not supported.\n")); 172 fExtDispReqSupport = false; 173 } 174 else 175 LogRelFlowFunc(("Got Extended Param from Host cx=%d, cy=%d, bpp=%d, iDisp=%d, OrgX=%d, OrgY=%d Enb=%d\n", 176 cx, cy, cBits, iDisplay, cxOrg, cyOrg, 177 fEnabled)); 178 } 179 if (!fExtDispReqSupport) 180 rc = VbglR3GetDisplayChangeRequest(&cx, &cy, &cBits, &iDisplay, 181 true); 182 if (RT_FAILURE(rc)) 183 FatalError(("Failed to retrieve size hint, rc=%Rrc\n", rc)); 184 if (iDisplay > INT32_MAX) 185 FatalError(("Received a hint for too high display number %u\n", 186 (unsigned) iDisplay)); 187 if (iDisplay >= cSizeHints) 188 { 189 uint32_t i; 190 191 paSizeHints = (long *)RTMemRealloc(paSizeHints, 192 (iDisplay + 1) 193 * sizeof(*paSizeHints)); 194 if (!paSizeHints) 195 FatalError(("Failed to re-allocate size hint memory.\n")); 196 for (i = cSizeHints; i < iDisplay + 1; ++i) 197 paSizeHints[i] = 0; 198 cSizeHints = iDisplay + 1; 199 } 200 if ((!fExtDispReqSupport || fEnabled) && cx != 0 && cy != 0) 201 { 202 paSizeHints[iDisplay] = (cx & 0xffff) << 16 | (cy & 0xffff); 203 XChangeProperty(pDisplay, DefaultRootWindow(pDisplay), 204 XInternAtom(pDisplay, "VBOX_SIZE_HINTS", 0), 205 XA_INTEGER, 32, PropModeReplace, 206 (unsigned char *)paSizeHints, cSizeHints); 207 XFlush(pDisplay); 208 } 209 if (!fHaveRandR12) 210 { 211 RTStrPrintf(szCommand, sizeof(szCommand), 212 "%s -s %ux%u", pcszXrandr, cx, cy); 213 status = system(szCommand); 214 if (WEXITSTATUS(status) != 0) 215 FatalError(("Failed to execute \\\"%s\\\".\n", szCommand)); 181 216 } 182 217 else 183 LogRelFlowFunc(("Got Extended Param from Host cx=%d, cy=%d, bpp=%d, iDisp=%d, " 184 "OrgX=%d, OrgY=%d Enb=%d\n", cx, cy, cBits, iDisplay, 185 cxOrg, cyOrg, fEnabled)); 186 /* If we are not stopping, sleep for a bit to avoid using up 187 too much CPU while retrying. */ 188 if (RT_FAILURE(rc2)) 189 RTThreadYield(); 190 else 191 if (RRMin < 2) 192 setSize(pDisplay, cx, cy); 193 else 218 { 219 if (fExtDispReqSupport && fEnabled) 194 220 { 195 char szCommand[256]; 196 if (fExtDispReqSupport) 197 { 198 if (fEnabled) 199 { 200 if (cx != 0 && cy != 0) 201 { 202 RTStrPrintf(szCommand, sizeof(szCommand), 203 "%s --output VGA-%u --set VBOX_MODE %d", 204 pcszXrandr, iDisplay, 205 (cx & 0xffff) << 16 | (cy & 0xffff)); 206 system(szCommand); 207 } 208 /* Extended Display support possible . Secondary monitor position supported */ 209 if (cxOrg != 0 || cyOrg != 0) 210 { 211 RTStrPrintf(szCommand, sizeof(szCommand), 212 "%s --output VGA-%u --auto --pos %dx%d", 213 pcszXrandr, iDisplay, cxOrg, cyOrg); 214 system(szCommand); 215 } 216 RTStrPrintf(szCommand, sizeof(szCommand), 217 "%s --output VGA-%u --preferred", 218 pcszXrandr, iDisplay); 219 system(szCommand); 220 } 221 else /* disable the virtual monitor */ 222 { 223 RTStrPrintf(szCommand, sizeof(szCommand), 224 "%s --output VGA-%u --off", 225 pcszXrandr, iDisplay); 226 system(szCommand); 227 } 228 } 229 else /* Extended display support not possible */ 230 { 231 if (cx != 0 && cy != 0) 232 { 233 RTStrPrintf(szCommand, sizeof(szCommand), 234 "%s --output VGA-%u --set VBOX_MODE %d", 235 pcszXrandr, iDisplay, 236 (cx & 0xffff) << 16 | (cy & 0xffff)); 237 system(szCommand); 238 RTStrPrintf(szCommand, sizeof(szCommand), 239 "%s --output VGA-%u --preferred", 240 pcszXrandr, iDisplay); 241 system(szCommand); 242 } 243 } 244 221 /* Extended Display support possible . Secondary monitor 222 * position supported */ 223 RTStrPrintf(szCommand, sizeof(szCommand), 224 "%s --output VGA-%u --auto --pos %dx%d", 225 pcszXrandr, iDisplay, cxOrg, cyOrg); 226 status = system(szCommand); 227 if (WEXITSTATUS(status) != 0) 228 FatalError(("Failed to execute \\\"%s\\\".\n", szCommand)); 245 229 } 230 if ((!fExtDispReqSupport || fEnabled) && cx != 0 && cy != 0) 231 { 232 RTStrPrintf(szCommand, sizeof(szCommand), 233 "%s --output VGA-%u --preferred", 234 pcszXrandr, iDisplay); 235 status = system(szCommand); 236 if (WEXITSTATUS(status) != 0) 237 FatalError(("Failed to execute \\\"%s\\\".\n", szCommand)); 238 } 239 if (fExtDispReqSupport && !fEnabled) 240 { 241 /* disable the virtual monitor */ 242 RTStrPrintf(szCommand, sizeof(szCommand), 243 "%s --output VGA-%u --off", 244 pcszXrandr, iDisplay); 245 status = system(szCommand); 246 if (WEXITSTATUS(status) != 0) 247 FatalError(("Failed to execute \\\"%s\\\".\n", szCommand)); 248 } 249 } 246 250 } 247 251 } … … 266 270 if (!mDisplay) 267 271 return VERR_NOT_FOUND; 268 rc = enableEventsAndCaps(mDisplay , true);272 rc = enableEventsAndCaps(mDisplay); 269 273 if (RT_SUCCESS(rc)) 270 274 mfInit = true; … … 288 292 if (!mfInit) 289 293 return VERR_WRONG_ORDER; 290 return enableEventsAndCaps(mDisplay , false);294 return enableEventsAndCaps(mDisplay); 291 295 } 292 296 virtual void cleanup()
Note:
See TracChangeset
for help on using the changeset viewer.