VirtualBox

Changeset 57356 in vbox


Ignore:
Timestamp:
Aug 14, 2015 3:03:30 PM (10 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
102119
Message:

Additions/x11: better handling of VT switching and mode hints.

Location:
trunk/src/VBox/Additions/x11
Files:
3 edited

Legend:

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

    r56322 r57356  
    2626#include <X11/Xatom.h>
    2727
     28#include <iprt/asm.h>
    2829#include <iprt/assert.h>
    2930#include <iprt/err.h>
     
    5455    bool fEnabled;
    5556    bool fUpdateSize;
    56     bool fUpdatePosition;
     57    volatile bool fUpdatePosition;
    5758};
    5859
     
    8485};
    8586
    86 /** Tell the VBoxGuest driver we no longer want any events and tell the host
    87  * we no longer support any capabilities. */
    88 static int disableEventsAndCaps(bool fDisableEvents)
    89 {
    90     int rc = VbglR3SetGuestCaps(0, VMMDEV_GUEST_SUPPORTS_GRAPHICS);
    91     if (RT_FAILURE(rc))
    92         VBClFatalError(("Failed to unset graphics capability, rc=%Rrc.\n", rc));
    93     rc = VbglR3SetMouseStatus(VMMDEV_MOUSE_GUEST_NEEDS_HOST_CURSOR);
    94     if (RT_FAILURE(rc))
    95         VBClFatalError(("Failed to unset mouse status, rc=%Rrc.\n", rc));
    96     if (fDisableEvents)
    97         rc = VbglR3CtlFilterMask(0, VMMDEV_EVENT_MOUSE_CAPABILITIES_CHANGED | VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST);
    98     if (RT_FAILURE(rc))
    99         VBClFatalError(("Failed to unset filter mask, rc=%Rrc.\n", rc));
    100     return VINF_SUCCESS;
    101 }
    102 
    103 /** Tell the VBoxGuest driver which events we want and tell the host which
    104  * capabilities we support. */
    105 static int enableEventsAndCaps()
    106 {
    107     int rc = VbglR3CtlFilterMask(  VMMDEV_EVENT_MOUSE_CAPABILITIES_CHANGED
    108                                  | VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST, 0);
    109     if (RT_FAILURE(rc))
    110         VBClFatalError(("Failed to set filter mask, rc=%Rrc.\n", rc));
    111     rc = VbglR3SetGuestCaps(VMMDEV_GUEST_SUPPORTS_GRAPHICS, 0);
    112     if (RT_FAILURE(rc))
    113         VBClFatalError(("Failed to set graphics capability, rc=%Rrc.\n", rc));
    114     rc = VbglR3SetMouseStatus(0);
    115     if (RT_FAILURE(rc))
    116         VBClFatalError(("Failed to set mouse status, rc=%Rrc.\n", rc));
     87/** Thread to monitor and react to X server VT switches and exits. */
     88static int pfnMonitorThread(RTTHREAD self, void *pvUser)
     89{
     90    struct DISPLAYSTATE *pState = (struct DISPLAYSTATE *)pvUser;
     91    Display *pDisplay;
     92    bool fHasVT = true;
     93
     94    pDisplay = XOpenDisplay(NULL);
     95    if (!pDisplay)
     96        VBClFatalError(("Failed to open the X11 display\n"));
     97    XSelectInput(pDisplay, DefaultRootWindow(pDisplay), PropertyChangeMask);
     98    while (true)
     99    {
     100        XEvent event;
     101
     102        XNextEvent(pDisplay, &event);
     103        /* This property is deleted when the server regains the virtual
     104         * terminal.  Force the main thread to call xrandr again, as old X
     105         * servers could not handle it while switched out. */
     106        if (pState->fHaveRandR12)
     107            continue;
     108        if (   event.type != PropertyNotify
     109            || event.xproperty.state != PropertyDelete
     110            || event.xproperty.window != DefaultRootWindow(pDisplay)
     111            || event.xproperty.atom != XInternAtom(pDisplay, "VBOXVIDEO_NO_VT", False))
     112            continue;
     113        LogRel(("VBoxClient/Display: entered virtual terminal.\n"));
     114        ASMAtomicWriteBool(&pState->paScreenInformation[0].fUpdateSize, true);
     115        VbglR3InterruptEventWaits();
     116    }
     117    return VINF_SUCCESS;  /* Should never be reached. */
     118}
     119
     120static int startMonitorThread(struct DISPLAYSTATE *pState)
     121{
     122    int rc;
     123
     124    rc = RTThreadCreate(NULL, pfnMonitorThread, (void *)pState, 0, RTTHREADTYPE_INFREQUENT_POLLER, 0, "VT_MONITOR");
     125    if (rc != VINF_SUCCESS)
     126        VBClFatalError(("Failed to start the VT monitor thread, rc=%Rrc\n", rc));
    117127    return VINF_SUCCESS;
    118128}
     
    209219        && pState->paScreenInformation[0].cx > 0 && pState->paScreenInformation[0].cy > 0)
    210220    {
     221        int ret;
     222
    211223        RTStrPrintf(szCommand, sizeof(szCommand), "%s -s %ux%u",
    212224                    pState->pcszXrandr, pState->paScreenInformation[0].cx, pState->paScreenInformation[0].cy);
    213         system(szCommand);
     225        ret = system(szCommand);
     226        LogRel(("VBoxClient/Display: executed \"%s\", returned %d.\n", szCommand, ret));
    214227        pState->paScreenInformation[0].fUpdateSize = false;
    215228    }
     
    238251    int rc;
    239252    unsigned i, cScreensTracked;
     253    uint32_t fModeSet = false;
    240254
    241255    LogRelFlowFunc(("\n"));
     
    262276        }
    263277    }
     278    /* Semantics: when VBOX_HAS_GRAPHICS is set, the X server driver assumes
     279     * that a client capable of forwarding mode hints will be present for the
     280     * rest of the X session.  If we crash things will not work as they should.
     281     * I thought that preferable to implementing complex crash-handling logic.
     282     */
     283    XChangeProperty(pState->pDisplay, DefaultRootWindow(pState->pDisplay), XInternAtom(pState->pDisplay, "VBOX_HAS_GRAPHICS", 0),
     284                    XA_INTEGER, 32, PropModeReplace, (unsigned char *)&fModeSet, 1);
    264285    while (true)
    265286    {
     
    333354    if (RT_FAILURE(rc))
    334355        return rc;
    335     rc = enableEventsAndCaps();
     356    rc = VbglR3CtlFilterMask(VMMDEV_EVENT_MOUSE_CAPABILITIES_CHANGED | VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST, 0);
     357    if (RT_FAILURE(rc))
     358        VBClFatalError(("Failed to set filter mask, rc=%Rrc.\n", rc));
    336359    if (RT_SUCCESS(rc))
    337360        pSelf->mfInit = true;
     
    346369    if (!pSelf->mfInit)
    347370        return VERR_WRONG_ORDER;
    348     rc = VBClStartVTMonitor();
     371    rc = startMonitorThread(pSelf);
    349372    if (RT_FAILURE(rc))
    350373        VBClFatalError(("Failed to start the VT monitor thread: %Rrc\n", rc));
     
    353376}
    354377
    355 static int pause(struct VBCLSERVICE **ppInterface)
    356 {
    357     struct DISPLAYSTATE *pSelf = getStateFromInterface(ppInterface);
    358 
    359     if (!pSelf->mfInit)
    360         return VERR_WRONG_ORDER;
    361     return disableEventsAndCaps(false);
    362 }
    363 
    364 static int resume(struct VBCLSERVICE **ppInterface)
    365 {
    366     struct DISPLAYSTATE *pSelf = getStateFromInterface(ppInterface);
    367     int rc;
    368 
    369     if (!pSelf->mfInit)
    370         return VERR_WRONG_ORDER;
    371     rc = enableEventsAndCaps();
    372     /* RandR 1.1-based drivers only let us change mode when we are not switched
    373      * out, so interrupt the wait when we switch in and re-set it. */
    374     VbglR3InterruptEventWaits();
    375     return rc;
    376 }
    377 
    378378static void cleanup(struct VBCLSERVICE **ppInterface)
    379379{
    380380    NOREF(ppInterface);
    381     disableEventsAndCaps(true);
     381    VbglR3CtlFilterMask(0, VMMDEV_EVENT_MOUSE_CAPABILITIES_CHANGED | VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST);
    382382    VbglR3Term();
    383383}
     
    388388    init,
    389389    run,
    390     pause,
    391     resume,
     390    VBClServiceDefaultHandler, /* pause */
     391    VBClServiceDefaultHandler, /* resume */
    392392    cleanup
    393393};
  • trunk/src/VBox/Additions/x11/undefined_xfree86

    r52651 r57356  
    8383defaultDPMSEnabled
    8484DeleteCallback
     85DeleteProperty
    8586DeliverEvents
    8687deltaSaveUndersViewable
  • trunk/src/VBox/Additions/x11/vboxvideo/vboxvideo.c

    r57180 r57356  
    5757#include "vboxvideo.h"
    5858#include <VBox/VBoxGuest.h>
     59#include <VBox/VBoxGuestLib.h>
    5960#include <VBox/Hardware/VBoxVideoVBE.h>
    6061#include "version-generated.h"
     
    9899# include <stdlib.h>
    99100# include <string.h>
    100 #endif
    101 
    102 /* This was accepted upstream in X.Org Server 1.16 which bumped the video
    103  * driver ABI to 17. */
    104 #if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 17
    105 # define SET_HAVE_VT_PROPERTY
    106101#endif
    107102
     
    300295
    301296/** Set a video mode to the hardware, RandR 1.1 version.  Since we no longer do
    302  * virtual frame buffers, adjust the screen pixmap dimensions to match. */
    303 static void setModeRandR11(ScrnInfoPtr pScrn, DisplayModePtr pMode, bool fScreenInitTime, bool fEnterVTTime)
     297 * virtual frame buffers, adjust the screen pixmap dimensions to match.  The
     298 * "override" parameters are for when we received a mode hint while switched to
     299 * a virtual terminal.  In this case VBoxClient will have told us about the
     300 * mode, but not yet been able to do a mode switch using RandR.  We solve this
     301 * by setting the requested mode to the host but keeping the virtual frame-
     302 * buffer matching what the X server expects. */
     303static void setModeRandR11(ScrnInfoPtr pScrn, DisplayModePtr pMode, bool fScreenInitTime, bool fEnterVTTime,
     304                           int cXOverRide, int cYOverRide)
    304305{
    305306    VBOXPtr pVBox = VBOXGetRec(pScrn);
    306307    struct vbvxFrameBuffer frameBuffer = { 0, 0, pMode->HDisplay, pMode->VDisplay, pScrn->bitsPerPixel};
     308    int cXPhysical = cXOverRide > 0 ? min(cXOverRide, pMode->HDisplay) : pMode->HDisplay;
     309    int cYPhysical = cYOverRide > 0 ? min(cYOverRide, pMode->VDisplay) : pMode->VDisplay;
    307310
    308311    pVBox->pScreens[0].aScreenLocation.cx = pMode->HDisplay;
     
    330333    }
    331334    if (pMode->HDisplay != 0 && pMode->VDisplay != 0 && pScrn->vtSema)
    332         vbvxSetMode(pScrn, 0, pMode->HDisplay, pMode->VDisplay, 0, 0, true, true, &frameBuffer);
     335        vbvxSetMode(pScrn, 0, cXPhysical, cYPhysical, 0, 0, true, true, &frameBuffer);
    333336    pScrn->currentMode = pMode;
    334337}
     
    996999}
    9971000
    998 #define HAS_VT_ATOM_NAME "XFree86_has_VT"
    999 #define VBOXVIDEO_DRIVER_ATOM_NAME "VBOXVIDEO_DRIVER_IN_USE"
    1000 /* The memory storing the initial value of the XFree86_has_VT root window
    1001  * property.  This has to remain available until server start-up, so we just
    1002  * use a global. */
    1003 static CARD32 InitialPropertyValue = 1;
    1004 
    1005 /** Initialise a flag property on the root window to say whether the server VT
    1006  *  is currently the active one as some clients need to know this. */
    1007 static void initialiseProperties(ScrnInfoPtr pScrn)
    1008 {
    1009     Atom atom = -1;
    1010     CARD32 *PropertyValue = &InitialPropertyValue;
    1011 #ifdef SET_HAVE_VT_PROPERTY
    1012     atom = MakeAtom(HAS_VT_ATOM_NAME, sizeof(HAS_VT_ATOM_NAME) - 1, TRUE);
    1013     if (xf86RegisterRootWindowProperty(pScrn->scrnIndex, atom, XA_INTEGER,
    1014                                        32, 1, PropertyValue) != Success)
    1015         FatalError("vboxvideo: failed to register VT property\n");
    1016 #endif /* SET_HAVE_VT_PROPERTY */
    1017     atom = MakeAtom(VBOXVIDEO_DRIVER_ATOM_NAME,
    1018                     sizeof(VBOXVIDEO_DRIVER_ATOM_NAME) - 1, TRUE);
    1019     if (xf86RegisterRootWindowProperty(pScrn->scrnIndex, atom, XA_INTEGER,
    1020                                        32, 1, PropertyValue) != Success)
    1021         FatalError("vboxvideo: failed to register driver in use property\n");
    1022 }
    1023 
    1024 #ifdef SET_HAVE_VT_PROPERTY
    1025 /** Update a flag property on the root window to say whether the server VT
    1026  *  is currently the active one as some clients need to know this. */
    1027 static void updateHasVTProperty(ScrnInfoPtr pScrn, Bool hasVT)
    1028 {
    1029     Atom property_name;
    1030     int32_t value = hasVT ? 1 : 0;
    1031     int i;
    1032 
    1033     property_name = MakeAtom(HAS_VT_ATOM_NAME, sizeof(HAS_VT_ATOM_NAME) - 1,
    1034                              FALSE);
    1035     if (property_name == BAD_RESOURCE)
    1036         FatalError("Failed to retrieve \"HAS_VT\" atom\n");
    1037     if (ROOT_WINDOW(pScrn) == NULL)
     1001/** Set the graphics and guest cursor support capabilities to the host if
     1002 *  the user-space helper is running. */
     1003static void updateGraphicsCapability(ScrnInfoPtr pScrn, Bool hasVT)
     1004{
     1005    VBOXPtr pVBox = VBOXGetRec(pScrn);
     1006    size_t cData;
     1007    int32_t *paData;
     1008    int rc;
     1009
     1010    if (pVBox->fHaveHGSMIModeHints)
    10381011        return;
    1039     ChangeWindowProperty(ROOT_WINDOW(pScrn), property_name, XA_INTEGER, 32,
    1040                          PropModeReplace, 1, &value, TRUE);
    1041 }
    1042 #endif /* SET_HAVE_VT_PROPERTY */
     1012    rc = vbvxGetIntegerPropery(pScrn, "VBOX_HAS_GRAPHICS", &cData, &paData);
     1013    if (rc != VINF_SUCCESS || cData != 1)
     1014        return;
     1015    if (RT_BOOL(*paData) != hasVT)
     1016    {
     1017        uint32_t fFeatures;
     1018        VbglR3SetGuestCaps(hasVT ? VMMDEV_GUEST_SUPPORTS_GRAPHICS : 0, hasVT ? 0 : VMMDEV_GUEST_SUPPORTS_GRAPHICS);
     1019        rc = VbglR3GetMouseStatus(&fFeatures, NULL, NULL);
     1020        fFeatures &= VMMDEV_MOUSE_GUEST_CAN_ABSOLUTE | VMMDEV_MOUSE_NEW_PROTOCOL;
     1021        if (RT_SUCCESS(rc))
     1022            VbglR3SetMouseStatus(hasVT ? fFeatures : fFeatures | VMMDEV_MOUSE_GUEST_NEEDS_HOST_CURSOR);
     1023    }
     1024    *paData = hasVT;
     1025}
    10431026
    10441027#ifdef VBOXVIDEO_13
     
    11691152 * Although this is far more often than necessary it should not have real-life
    11701153 * performance consequences and allows us to simplify the code quite a bit. */
    1171 static void updateSizeHintsBlockHandler(pointer pData, OSTimePtr pTimeout, pointer pReadmask)
     1154static void vboxBlockHandler(pointer pData, OSTimePtr pTimeout, pointer pReadmask)
    11721155{
    11731156    ScrnInfoPtr pScrn = (ScrnInfoPtr)pData;
     
    11771160    (void)pTimeout;
    11781161    (void)pReadmask;
    1179     if (!pScrn->vtSema)
    1180         return;
    1181     vbvxReadSizesAndCursorIntegrationFromHGSMI(pScrn, &fNeedUpdate);
     1162    updateGraphicsCapability(pScrn, pScrn->vtSema);
     1163    if (pScrn->vtSema)
     1164        vbvxReadSizesAndCursorIntegrationFromHGSMI(pScrn, &fNeedUpdate);
     1165    /* This has to be done even when we are switched out so that VBoxClient can
     1166     * set a mode using RandR without having to know the virtual terminal state.
     1167     */
    11821168    if (ROOT_WINDOW(pScrn) != NULL)
    11831169        vbvxReadSizesAndCursorIntegrationFromProperties(pScrn, &fNeedUpdate);
     
    12081194    TRACE_ENTRY();
    12091195
     1196    /* Initialise our guest library if possible: ignore failure. */
     1197    VbglR3Init();
    12101198    if (!VBOXMapVidMem(pScrn))
    12111199        return (FALSE);
     
    13401328#else
    13411329    /* set first video mode */
    1342     setModeRandR11(pScrn, pScrn->currentMode, true, false);
     1330    setModeRandR11(pScrn, pScrn->currentMode, true, false, 0, 0);
    13431331#endif
    13441332
    13451333    /* Register block and wake-up handlers for getting new screen size hints. */
    1346     RegisterBlockAndWakeupHandlers(updateSizeHintsBlockHandler, (WakeupHandlerProcPtr)NoopDDA, (pointer)pScrn);
     1334    RegisterBlockAndWakeupHandlers(vboxBlockHandler, (WakeupHandlerProcPtr)NoopDDA, (pointer)pScrn);
    13471335
    13481336    /* software cursor */
     
    13851373#endif
    13861374
    1387     initialiseProperties(pScrn);
    1388 
    13891375    return (TRUE);
    13901376}
    13911377
     1378#define NO_VT_ATOM_NAME "VBOXVIDEO_NO_VT"
     1379
    13921380static Bool VBOXEnterVT(ScrnInfoPtr pScrn)
    13931381{
    13941382    VBOXPtr pVBox = VBOXGetRec(pScrn);
     1383#ifndef VBOXVIDEO_13
     1384    /* If we got a mode request while we were switched out, temporarily override
     1385     * the physical mode set to the device while keeping things consistent from
     1386     * the server's point of view. */
     1387    int cXOverRide = RT_CLAMP(pVBox->pScreens[0].aPreferredSize.cx, VBOX_VIDEO_MIN_SIZE, VBOX_VIDEO_MAX_VIRTUAL);
     1388    int cYOverRide = RT_CLAMP(pVBox->pScreens[0].aPreferredSize.cy, VBOX_VIDEO_MIN_SIZE, VBOX_VIDEO_MAX_VIRTUAL);
     1389#endif
    13951390
    13961391    TRACE_ENTRY();
     1392    updateGraphicsCapability(pScrn, TRUE);
    13971393#ifdef VBOX_DRI_OLD
    13981394    if (pVBox->useDRI)
     
    14101406#ifdef VBOXVIDEO_13
    14111407    vbvxReadSizesAndCursorIntegrationFromHGSMI(pScrn, NULL);
    1412     vbvxReadSizesAndCursorIntegrationFromProperties(pScrn, NULL);
    14131408    setSizesAndCursorIntegration(pScrn, false);
    14141409#else
    1415     setModeRandR11(pScrn, pScrn->currentMode, false, true);
    1416 #endif
    1417 #ifdef SET_HAVE_VT_PROPERTY
    1418     updateHasVTProperty(pScrn, TRUE);
     1410    setModeRandR11(pScrn, pScrn->currentMode, false, true, cXOverRide, cYOverRide);
     1411    DeleteProperty(ROOT_WINDOW(pScrn), MakeAtom(NO_VT_ATOM_NAME, sizeof(NO_VT_ATOM_NAME) - 1, TRUE));
    14191412#endif
    14201413    return TRUE;
     
    14261419#ifdef VBOXVIDEO_13
    14271420    unsigned i;
     1421#else
     1422    int32_t propertyValue = 0;
    14281423#endif
    14291424
    14301425    TRACE_ENTRY();
     1426    updateGraphicsCapability(pScrn, FALSE);
    14311427#ifdef VBOXVIDEO_13
    14321428    for (i = 0; i < pVBox->cScreens; ++i)
    14331429        vbox_crtc_dpms(pVBox->pScreens[i].paCrtcs, DPMSModeOff);
     1430#else
     1431    ChangeWindowProperty(ROOT_WINDOW(pScrn), MakeAtom(NO_VT_ATOM_NAME, sizeof(NO_VT_ATOM_NAME) - 1, FALSE), XA_INTEGER, 32,
     1432                         PropModeReplace, 1, &propertyValue, TRUE);
    14341433#endif
    14351434    vboxDisableVbva(pScrn);
     
    14431442#endif
    14441443    VBOXRestoreMode(pScrn);
    1445 #ifdef SET_HAVE_VT_PROPERTY
    1446     updateHasVTProperty(pScrn, FALSE);
    1447 #endif
    14481444    TRACE_EXIT();
    14491445}
     
    14561452    BOOL fRestore = TRUE;
    14571453#endif
     1454    BOOL ret;
     1455
    14581456    if (pScrn->vtSema)
    14591457    {
     
    14941492#endif
    14951493#ifndef XF86_SCRN_INTERFACE
    1496     return pScreen->CloseScreen(pScreen->myNum, pScreen);
    1497 #else
    1498     return pScreen->CloseScreen(pScreen);
    1499 #endif
     1494    ret = pScreen->CloseScreen(pScreen->myNum, pScreen);
     1495#else
     1496    ret = pScreen->CloseScreen(pScreen);
     1497#endif
     1498    VbglR3Term();
     1499    return ret;
    15001500}
    15011501
     
    15081508    rc = xf86SetSingleMode(pScrn, pMode, RR_Rotate_0);
    15091509#else
    1510     setModeRandR11(pScrn, pMode, false, false);
     1510    setModeRandR11(pScrn, pMode, false, false, 0, 0);
    15111511#endif
    15121512    TRACE_LOG("returning %s\n", rc ? "TRUE" : "FALSE");
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