Logo Search packages:      
Sourcecode: virtualbox-ose version File versions

int main ( int  argc,
char *  argv[] 
)

entry point

The initial and most common state, pass keystrokes to the guest. Next state: HKEYSTATE_DOWN Prev state: Any

The first host key was pressed down

The second host key was pressed down (if gHostKeySym2 != SDLK_UNKNOWN)

The host key has been pressed down. Prev state: HKEYSTATE_NORMAL Next state: HKEYSTATE_NORMAL - host key up, capture toggle. Next state: HKEYSTATE_USED - host key combination down. Next state: HKEYSTATE_NOT_IT - non-host key combination down.

A host key combination was pressed. Prev state: HKEYSTATE_DOWN Next state: HKEYSTATE_NORMAL - when modifiers are all 0

A non-host key combination was attempted. Send hostkey down to the guest and continue until all modifiers have been released. Prev state: HKEYSTATE_DOWN Next state: HKEYSTATE_NORMAL - when modifiers are all 0

The host key down event which we have been hiding from the guest. Used when going from HKEYSTATE_DOWN to HKEYSTATE_NOT_IT.

Todo:

Todo:
why is this attachment saved?

Todo:
that somehow doesn't seem to work!

Todo:
use a common user event handler so that SDL_PeepEvents() won't possibly remove other events in the queue!

Todo:
This is a workaround for synchronization problems between EMT and the SDL main thread. It can happen that the SDL thread already starts a new resize operation while the EMT is still busy with the old one leading to a deadlock. Therefore we call SetVideoModeHint only once when the mouse button was released.

Definition at line 710 of file VBoxSDL.cpp.

References com::Bstr::asOutParam(), com::Guid::asOutParam(), ComPtrBase< I, RefOps >::asOutParam(), ComPtrBase< C, RefOps >::asOutParam(), Assert, AssertComRC, AssertMsg, AssertMsgFailed, AssertReleaseRC, CHECK_ERROR, CHECK_ERROR_BREAK, ComPtr< I, RefOps >::createInprocObject(), ComPtr< I, RefOps >::createLocalObject(), CSAMEnabled(), DVDDrives(), FloppyDrives(), com::ErrorInfo::getComponent(), com::ErrorInfo::getText(), HandleGuestCapsChanged(), HandleHostKey(), HKEYSTATE_DOWN, HKEYSTATE_NORMAL, HKEYSTATE_NOT_IT, HKEYSTATE_USED, HostInterface(), HWVirtExEnabled(), Id(), VBoxSDLConsoleCallback::ignorePowerOffEvents(), InputGrabEnd(), InputGrabStart(), com::ErrorInfo::isBasicAvailable(), com::Guid::isEmpty(), com::ErrorInfo::isFullAvailable(), Log, LogBird, LogFlow, LogRel, MemorySize(), NetworkAdapterCount, NULL, PATMEnabled(), Port(), ProcessKey(), com::Guid::ptr(), com::Utf8Str::raw(), com::Bstr::raw(), RecompileSupervisor(), RecompileUser(), ResetKeys(), ResizeTimer(), RT_MAX, SDL_USER_EVENT_GUEST_CAP_CHANGED, SDL_USER_EVENT_POINTER_CHANGE, SDL_USER_EVENT_RESIZE, SDL_USER_EVENT_SECURELABEL_UPDATE, SDL_USER_EVENT_TERMINATE, SDL_USER_EVENT_TIMER, SDL_USER_EVENT_UPDATE_TITLEBAR, SDL_USER_EVENT_UPDATERECT, SDL_USER_EVENT_WINDOW_RESIZE_DONE, SDL_USER_EVENT_XPCOM_EVENTQUEUE, SendMouseEvent(), SetPointerShape(), show_usage(), StartupTimer(), strncmp(), UpdateTitlebar(), UseAbsoluteMouse(), VBOX_FAILURE, VBOX_SUCCESS, VBOXSDL_TERM_NORMAL, VINF_SUCCESS, VirtualTimeRate(), and WaitSDLEvent().

{
    /*
     * Before we do *anything*, we initialize the runtime.
     */
    int rcRT = RTR3Init(true, ~(size_t)0);
    if (VBOX_FAILURE(rcRT))
    {
        RTPrintf("Error: RTR3Init failed rcRC=%d\n", rcRT);
        return 1;
    }

#ifdef RT_OS_LINUX
    /*
     * Lock keys on SDL behave different from normal keys: A KeyPress event is generated
     * if the lock mode gets active and a keyRelease event is genereated if the lock mode
     * gets inactive, that is KeyPress and KeyRelease are sent when pressing the lock key
     * to change the mode. The current lock mode is reflected in SDL_GetModState().
     *
     * Debian patched libSDL to make the lock keys behave like normal keys generating a
     * KeyPress/KeyRelease event if the lock key was pressed/released. But the lock status
     * is not reflected in the mod status anymore. We disable the Debian-specific extension
     * to ensure a defined environment and work around the missing KeyPress/KeyRelease
     * events in ProcessKeys().
     */
    setenv("SDL_DISABLE_LOCK_KEYS", "1", 1);
#endif

    /*
     * the hostkey detection mode is unrelated to VM processing, so handle it before
     * we initialize anything COM related
     */
    if (argc == 2 && !strcmp(argv[1], "-detecthostkey"))
    {
        int rc = SDL_InitSubSystem(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_NOPARACHUTE);
        if (rc != 0)
        {
            RTPrintf("Error: SDL_InitSubSystem failed with message '%s'\n", SDL_GetError());
            return 1;
        }
        /* we need a video window for the keyboard stuff to work */
        if (!SDL_SetVideoMode(640, 480, 16, SDL_SWSURFACE))
        {
            RTPrintf("Error: could not set SDL video mode\n");
            return 1;
        }

        RTPrintf("Please hit one or two function key(s) to get the -hostkey value...\n");

        SDL_Event event1;
        while (SDL_WaitEvent(&event1))
        {
            if (event1.type == SDL_KEYDOWN)
            {
                SDL_Event event2;
                unsigned  mod = SDL_GetModState() & ~(KMOD_MODE | KMOD_NUM | KMOD_RESERVED);
                while (SDL_WaitEvent(&event2))
                {
                    if (event2.type == SDL_KEYDOWN || event2.type == SDL_KEYUP)
                    {
                        /* pressed additional host key */
                        RTPrintf("-hostkey %d", event1.key.keysym.sym);
                        if (event2.type == SDL_KEYDOWN)
                        {
                            RTPrintf(" %d", event2.key.keysym.sym);
                            RTPrintf(" %d\n", SDL_GetModState() & ~(KMOD_MODE | KMOD_NUM | KMOD_RESERVED));
                        }
                        else
                        {
                            RTPrintf(" %d\n", mod);
                        }
                        /* we're done */
                        break;
                    }
                }
                /* we're down */
                break;
            }
        }
        SDL_Quit();
        return 1;
    }

    HRESULT rc;
    Guid uuid;
    char *vmName = NULL;
    DeviceType_T bootDevice = DeviceType_NoDevice;
    uint32_t memorySize = 0;
    uint32_t vramSize = 0;
    VBoxSDLCallback *callback = NULL;
    VBoxSDLConsoleCallback *consoleCallback = NULL;
    bool fFullscreen = false;
    bool fResizable = true;
#ifdef USE_XPCOM_QUEUE_THREAD
    bool fXPCOMEventThreadSignaled = false;
#endif
    char *hdaFile   = NULL;
    char *cdromFile = NULL;
    char *fdaFile   = NULL;
#ifdef VBOX_VRDP
    int portVRDP = ~0;
#endif
    bool fDiscardState = false;
#ifdef VBOX_SECURELABEL
    BOOL fSecureLabel = false;
    uint32_t secureLabelPointSize = 12;
    char *secureLabelFontFile = NULL;
    uint32_t secureLabelColorFG = 0x0000FF00;
    uint32_t secureLabelColorBG = 0x00FFFF00;
#endif
#ifdef VBOXSDL_ADVANCED_OPTIONS
    unsigned fRawR0 = ~0U;
    unsigned fRawR3 = ~0U;
    unsigned fPATM  = ~0U;
    unsigned fCSAM  = ~0U;
    TriStateBool_T fHWVirt = TriStateBool_Default;
    uint32_t u32WarpDrive = 0;
#endif
#ifdef VBOX_WIN32_UI
    bool fWin32UI = false;
#endif
    bool fShowSDLConfig    = false;
    uint32_t fixedWidth    = ~(uint32_t)0;
    uint32_t fixedHeight   = ~(uint32_t)0;
    uint32_t fixedBPP      = ~(uint32_t)0;
    uint32_t uResizeWidth  = ~(uint32_t)0;
    uint32_t uResizeHeight = ~(uint32_t)0;

    /* The damned GOTOs forces this to be up here - totally out of place. */
    /*
     * Host key handling.
     *
     * The golden rule is that host-key combinations should not be seen
     * by the guest. For instance a CAD should not have any extra RCtrl down
     * and RCtrl up around itself. Nor should a resume be followed by a Ctrl-P
     * that could encourage applications to start printing.
     *
     * We must not confuse the hostkey processing into any release sequences
     * either, the host key is supposed to be explicitly pressing one key.
     *
     * Quick state diagram:
     *
     *            host key down alone
     *  (Normal) ---------------
     *    ^ ^                  |
     *    | |                  v          host combination key down
     *    | |            (Host key down) ----------------
     *    | | host key up v    |                        |
     *    | |--------------    | other key down         v           host combination key down
     *    |                    |                  (host key used) -------------
     *    |                    |                        |      ^              |
     *    |              (not host key)--               |      |---------------
     *    |                    |     |  |               |
     *    |                    |     ---- other         |
     *    |  modifiers = 0     v                        v
     *    -----------------------------------------------
     */
    enum HKEYSTATE
    {
        /** The initial and most common state, pass keystrokes to the guest.
         * Next state: HKEYSTATE_DOWN
         * Prev state: Any */
        HKEYSTATE_NORMAL = 1,
        /** The first host key was pressed down
         */
        HKEYSTATE_DOWN_1ST,
        /** The second host key was pressed down (if gHostKeySym2 != SDLK_UNKNOWN)
         */
        HKEYSTATE_DOWN_2ND,
        /** The host key has been pressed down.
         * Prev state: HKEYSTATE_NORMAL
         * Next state: HKEYSTATE_NORMAL - host key up, capture toggle.
         * Next state: HKEYSTATE_USED   - host key combination down.
         * Next state: HKEYSTATE_NOT_IT - non-host key combination down.
         */
        HKEYSTATE_DOWN,
        /** A host key combination was pressed.
         * Prev state: HKEYSTATE_DOWN
         * Next state: HKEYSTATE_NORMAL - when modifiers are all 0
         */
        HKEYSTATE_USED,
        /** A non-host key combination was attempted. Send hostkey down to the
         * guest and continue until all modifiers have been released.
         * Prev state: HKEYSTATE_DOWN
         * Next state: HKEYSTATE_NORMAL - when modifiers are all 0
         */
        HKEYSTATE_NOT_IT
    } enmHKeyState = HKEYSTATE_NORMAL;
    /** The host key down event which we have been hiding from the guest.
     * Used when going from HKEYSTATE_DOWN to HKEYSTATE_NOT_IT. */
    SDL_Event EvHKeyDown1;
    SDL_Event EvHKeyDown2;

    LogFlow(("SDL GUI started\n"));
    RTPrintf("VirtualBox SDL GUI %s built %s %s\n",
             VBOX_VERSION_STRING, __DATE__, __TIME__);

    // less than one parameter is not possible
    if (argc < 2)
    {
        show_usage();
        return 1;
    }

    rc = com::Initialize();
    if (FAILED(rc))
    {
        RTPrintf("Error: COM initialization failed, rc = 0x%x!\n", rc);
        return 1;
    }

    do
    {
    // scopes all the stuff till shutdown
    ////////////////////////////////////////////////////////////////////////////

    ComPtr <IVirtualBox> virtualBox;
    ComPtr <ISession> session;
    bool sessionOpened = false;

    rc = virtualBox.createLocalObject (CLSID_VirtualBox);
    if (FAILED(rc))
    {
        com::ErrorInfo info;
        if (info.isFullAvailable())
            PrintError("Failed to create VirtualBox object",
                       info.getText().raw(), info.getComponent().raw());
        else
            RTPrintf("Failed to create VirtualBox object! No error information available (rc = 0x%x).\n", rc);
        break;
    }
    rc = session.createInprocObject (CLSID_Session);
    if (FAILED(rc))
    {
        RTPrintf("Failed to create session object, rc = 0x%x!\n", rc);
        break;
    }

    // create the event queue
    // (here it is necessary only to process remaining XPCOM/IPC events
    // after the session is closed)
    /// @todo
//    EventQueue eventQ;

#ifdef USE_XPCOM_QUEUE_THREAD
    nsCOMPtr<nsIEventQueue> eventQ;
    NS_GetMainEventQ(getter_AddRefs(eventQ));
#endif /* USE_XPCOM_QUEUE_THREAD */

    /* Get the number of network adapters */
    ULONG NetworkAdapterCount = 0;
    ComPtr <ISystemProperties> sysInfo;
    virtualBox->COMGETTER(SystemProperties) (sysInfo.asOutParam());
    sysInfo->COMGETTER (NetworkAdapterCount) (&NetworkAdapterCount);

#if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN)
    std::vector <Bstr> tapdev (NetworkAdapterCount);
    std::vector <int> tapfd (NetworkAdapterCount, 0);
#endif

    // command line argument parsing stuff
    for (int curArg = 1; curArg < argc; curArg++)
    {
        if (   strcmp(argv[curArg], "-vm") == 0
            || strcmp(argv[curArg], "-startvm") == 0)
        {
            if (++curArg >= argc)
            {
                RTPrintf("Error: VM not specified (UUID or name)!\n");
                rc = E_FAIL;
                break;
            }
            // first check if a UUID was supplied
            if (VBOX_FAILURE(RTUuidFromStr(uuid.ptr(), argv[curArg])))
            {
                LogFlow(("invalid UUID format, assuming it's a VM name\n"));
                vmName = argv[curArg];
            }
        }
        else if (strcmp(argv[curArg], "-boot") == 0)
        {
            if (++curArg >= argc)
            {
                RTPrintf("Error: missing argument for boot drive!\n");
                rc = E_FAIL;
                break;
            }
            switch (argv[curArg][0])
            {
                case 'a':
                {
                    bootDevice = DeviceType_FloppyDevice;
                    break;
                }

                case 'c':
                {
                    bootDevice = DeviceType_HardDiskDevice;
                    break;
                }

                case 'd':
                {
                    bootDevice = DeviceType_DVDDevice;
                    break;
                }

                default:
                {
                    RTPrintf("Error: wrong argument for boot drive!\n");
                    rc = E_FAIL;
                    break;
                }
            }
            if (FAILED (rc))
                break;
        }
        else if (strcmp(argv[curArg], "-m") == 0)
        {
            if (++curArg >= argc)
            {
                RTPrintf("Error: missing argument for memory size!\n");
                rc = E_FAIL;
                break;
            }
            memorySize = atoi(argv[curArg]);
        }
        else if (strcmp(argv[curArg], "-vram") == 0)
        {
            if (++curArg >= argc)
            {
                RTPrintf("Error: missing argument for vram size!\n");
                rc = E_FAIL;
                break;
            }
            vramSize = atoi(argv[curArg]);
        }
        else if (strcmp(argv[curArg], "-fullscreen") == 0)
        {
            fFullscreen = true;
        }
        else if (strcmp(argv[curArg], "-fixedmode") == 0)
        {
            /* three parameters follow */
            if (curArg + 3 >= argc)
            {
                RTPrintf("Error: missing arguments for fixed video mode!\n");
                rc = E_FAIL;
                break;
            }
            fixedWidth  = atoi(argv[++curArg]);
            fixedHeight = atoi(argv[++curArg]);
            fixedBPP    = atoi(argv[++curArg]);
        }
        else if (strcmp(argv[curArg], "-nofstoggle") == 0)
        {
            gfAllowFullscreenToggle = FALSE;
        }
        else if (strcmp(argv[curArg], "-noresize") == 0)
        {
            fResizable = false;
        }
        else if (strcmp(argv[curArg], "-nohostkey") == 0)
        {
            gHostKeyMod  = 0;
            gHostKeySym1 = 0;
        }
        else if (strcmp(argv[curArg], "-nograbonclick") == 0)
        {
            gfGrabOnMouseClick = FALSE;
        }
        else if (strcmp(argv[curArg], "-hda") == 0)
        {
            if (++curArg >= argc)
            {
                RTPrintf("Error: missing file name for first hard disk!\n");
                rc = E_FAIL;
                break;
            }
            /* resolve it. */
            if (RTPathExists(argv[curArg]))
                hdaFile = RTPathRealDup(argv[curArg]);
            if (!hdaFile)
            {
                RTPrintf("Error: The path to the specified harddisk, '%s', could not be resolved.\n", argv[curArg]);
                rc = E_FAIL;
                break;
            }
        }
        else if (strcmp(argv[curArg], "-fda") == 0)
        {
            if (++curArg >= argc)
            {
                RTPrintf("Error: missing file/device name for first floppy disk!\n");
                rc = E_FAIL;
                break;
            }
            /* resolve it. */
            if (RTPathExists(argv[curArg]))
                fdaFile = RTPathRealDup(argv[curArg]);
            if (!fdaFile)
            {
                RTPrintf("Error: The path to the specified floppy disk, '%s', could not be resolved.\n", argv[curArg]);
                rc = E_FAIL;
                break;
            }
        }
        else if (strcmp(argv[curArg], "-cdrom") == 0)
        {
            if (++curArg >= argc)
            {
                RTPrintf("Error: missing file/device name for cdrom!\n");
                rc = E_FAIL;
                break;
            }
            /* resolve it. */
            if (RTPathExists(argv[curArg]))
                cdromFile = RTPathRealDup(argv[curArg]);
            if (!cdromFile)
            {
                RTPrintf("Error: The path to the specified cdrom, '%s', could not be resolved.\n", argv[curArg]);
                rc = E_FAIL;
                break;
            }
        }
#if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN)
        else if (strncmp(argv[curArg], "-tapdev", 7) == 0)
        {
            ULONG n = 0;
            if (!argv[curArg][7] || ((n = strtoul(&argv[curArg][7], NULL, 10)) < 1) ||
                (n > NetworkAdapterCount) || (argc <= (curArg + 1)))
            {
                RTPrintf("Error: invalid TAP device option!\n");
                rc = E_FAIL;
                break;
            }
            tapdev[n - 1] = argv[curArg + 1];
            curArg++;
        }
        else if (strncmp(argv[curArg], "-tapfd", 6) == 0)
        {
            ULONG n = 0;
            if (!argv[curArg][6] || ((n = strtoul(&argv[curArg][6], NULL, 10)) < 1) ||
                (n > NetworkAdapterCount) || (argc <= (curArg + 1)))
            {
                RTPrintf("Error: invalid TAP file descriptor option!\n");
                rc = E_FAIL;
                break;
            }
            tapfd[n - 1] = atoi(argv[curArg + 1]);
            curArg++;
        }
#endif /* RT_OS_LINUX || RT_OS_DARWIN */
#ifdef VBOX_VRDP
        else if (strcmp(argv[curArg], "-vrdp") == 0)
        {
            // start with the standard VRDP port
            portVRDP = 0;

            // is there another argument
            if (argc > (curArg + 1))
            {
                // check if the next argument is a number
                int port = atoi(argv[curArg + 1]);
                if (port > 0)
                {
                    curArg++;
                    portVRDP = port;
                    LogFlow(("Using non standard VRDP port %d\n", portVRDP));
                }
            }
        }
#endif /* VBOX_VRDP */
        else if (strcmp(argv[curArg], "-discardstate") == 0)
        {
            fDiscardState = true;
        }
#ifdef VBOX_SECURELABEL
        else if (strcmp(argv[curArg], "-securelabel") == 0)
        {
            fSecureLabel = true;
            LogFlow(("Secure labelling turned on\n"));
        }
        else if (strcmp(argv[curArg], "-seclabelfnt") == 0)
        {
            if (++curArg >= argc)
            {
                RTPrintf("Error: missing font file name for secure label!\n");
                rc = E_FAIL;
                break;
            }
            secureLabelFontFile = argv[curArg];
        }
        else if (strcmp(argv[curArg], "-seclabelsiz") == 0)
        {
            if (++curArg >= argc)
            {
                RTPrintf("Error: missing font point size for secure label!\n");
                rc = E_FAIL;
                break;
            }
            secureLabelPointSize = atoi(argv[curArg]);
        }
        else if (strcmp(argv[curArg], "-seclabelfgcol") == 0)
        {
            if (++curArg >= argc)
            {
                RTPrintf("Error: missing text color value for secure label!\n");
                rc = E_FAIL;
                break;
            }
            sscanf(argv[curArg], "%X", &secureLabelColorFG);
        }
        else if (strcmp(argv[curArg], "-seclabelbgcol") == 0)
        {
            if (++curArg >= argc)
            {
                RTPrintf("Error: missing background color value for secure label!\n");
                rc = E_FAIL;
                break;
            }
            sscanf(argv[curArg], "%X", &secureLabelColorBG);
        }
#endif
#ifdef VBOXSDL_ADVANCED_OPTIONS
        else if (strcmp(argv[curArg], "-rawr0") == 0)
            fRawR0 = true;
        else if (strcmp(argv[curArg], "-norawr0") == 0)
            fRawR0 = false;
        else if (strcmp(argv[curArg], "-rawr3") == 0)
            fRawR3 = true;
        else if (strcmp(argv[curArg], "-norawr3") == 0)
            fRawR3 = false;
        else if (strcmp(argv[curArg], "-patm") == 0)
            fPATM = true;
        else if (strcmp(argv[curArg], "-nopatm") == 0)
            fPATM = false;
        else if (strcmp(argv[curArg], "-csam") == 0)
            fCSAM = true;
        else if (strcmp(argv[curArg], "-nocsam") == 0)
            fCSAM = false;
        else if (strcmp(argv[curArg], "-hwvirtex") == 0)
            fHWVirt = TriStateBool_True;
        else if (strcmp(argv[curArg], "-nohwvirtex") == 0)
            fHWVirt = TriStateBool_False;
        else if (strcmp(argv[curArg], "-warpdrive") == 0)
        {
            if (++curArg >= argc)
            {
                RTPrintf("Error: missing the rate value for the -warpdrive option!\n");
                rc = E_FAIL;
                break;
            }
            u32WarpDrive = RTStrToUInt32(argv[curArg]);
            if (u32WarpDrive < 2 || u32WarpDrive > 20000)
            {
                RTPrintf("Error: the warp drive rate is restricted to [2..20000]. (%d)\n", u32WarpDrive);
                rc = E_FAIL;
                break;
            }
        }
#endif /* VBOXSDL_ADVANCED_OPTIONS */
#ifdef VBOX_WIN32_UI
        else if (strcmp(argv[curArg], "-win32ui") == 0)
            fWin32UI = true;
#endif
        else if (strcmp(argv[curArg], "-showsdlconfig") == 0)
            fShowSDLConfig = true;
        else if (strcmp(argv[curArg], "-hostkey") == 0)
        {
            if (++curArg + 1 >= argc)
            {
                RTPrintf("Error: not enough arguments for host keys!\n");
                rc = E_FAIL;
                break;
            }
            gHostKeySym1 = atoi(argv[curArg++]);
            if (curArg + 1 < argc && (argv[curArg+1][0] == '0' || atoi(argv[curArg+1]) > 0))
            {
                /* two-key sequence as host key specified */
                gHostKeySym2 = atoi(argv[curArg++]);
            }
            gHostKeyMod = atoi(argv[curArg]);
        }
        /* just show the help screen */
        else
        {
            RTPrintf("Error: unrecognized switch '%s'\n", argv[curArg]);
            show_usage();
            return 1;
        }
    }
    if (FAILED (rc))
        break;

    /*
     * Do we have a name but no UUID?
     */
    if (vmName && uuid.isEmpty())
    {
        ComPtr<IMachine> aMachine;
        Bstr  bstrVMName = vmName;
        rc = virtualBox->FindMachine(bstrVMName, aMachine.asOutParam());
        if ((rc == S_OK) && aMachine)
        {
            aMachine->COMGETTER(Id)(uuid.asOutParam());
        }
        else
        {
            RTPrintf("Error: machine with the given ID not found!\n");
            goto leave;
        }
    }
    else if (uuid.isEmpty())
    {
        RTPrintf("Error: no machine specified!\n");
        goto leave;
    }

    /* create SDL event semaphore */
    rc = RTSemEventCreate(&g_EventSemSDLEvents);
    AssertReleaseRC(rc);

    rc = virtualBox->OpenSession(session, uuid);
    if (FAILED(rc))
    {
        com::ErrorInfo info;
        if (info.isFullAvailable())
            PrintError("Could not open VirtualBox session",
                    info.getText().raw(), info.getComponent().raw());
        goto leave;
    }
    if (!session)
    {
        RTPrintf("Could not open VirtualBox session!\n");
        goto leave;
    }
    sessionOpened = true;
    // get the VM we're dealing with
    session->COMGETTER(Machine)(gMachine.asOutParam());
    if (!gMachine)
    {
        com::ErrorInfo info;
        if (info.isFullAvailable())
            PrintError("Cannot start VM!",
                       info.getText().raw(), info.getComponent().raw());
        else
            RTPrintf("Error: given machine not found!\n");
        goto leave;
    }
    // get the VM console
    session->COMGETTER(Console)(gConsole.asOutParam());
    if (!gConsole)
    {
        RTPrintf("Given console not found!\n");
        goto leave;
    }

    /*
     * Are we supposed to use a different hard disk file?
     */
    if (hdaFile)
    {
        /*
         * Strategy: iterate through all registered hard disk
         * and see if one of them points to the same file. If
         * so, assign it. If not, register a new image and assing
         * it to the VM.
         */
        Bstr hdaFileBstr = hdaFile;
        ComPtr<IHardDisk> hardDisk;
        virtualBox->FindHardDisk(hdaFileBstr, hardDisk.asOutParam());
        if (!hardDisk)
        {
            /* we've not found the image */
            RTPrintf("Registering hard disk image '%S'...\n", hdaFile);
            virtualBox->OpenHardDisk (hdaFileBstr, hardDisk.asOutParam());
            if (hardDisk)
                virtualBox->RegisterHardDisk (hardDisk);
        }
        /* do we have the right image now? */
        if (hardDisk)
        {
            /*
             * Go and attach it!
             */
            Guid uuid;
            hardDisk->COMGETTER(Id)(uuid.asOutParam());
            gMachine->DetachHardDisk(DiskControllerType_IDE0Controller, 0);
            gMachine->AttachHardDisk(uuid, DiskControllerType_IDE0Controller, 0);
            /// @todo why is this attachment saved?
        }
        else
        {
            RTPrintf("Error: failed to mount the specified hard disk image!\n");
            goto leave;
        }
    }

    /*
     * Mount a floppy if requested.
     */
    if (fdaFile)
    do
    {
        ComPtr<IFloppyDrive> drive;
        CHECK_ERROR_BREAK (gMachine, COMGETTER(FloppyDrive)(drive.asOutParam()));

        /*
         * First special case 'none' to unmount
         */
        if (strcmp (fdaFile, "none") == 0)
        {
            CHECK_ERROR_BREAK (drive, Unmount());
            break;
        }

        Bstr media = fdaFile;
        bool done = false;

        /* Assume it's a host drive name */
        {
            ComPtr <IHost> host;
            CHECK_ERROR_BREAK (virtualBox, COMGETTER(Host)(host.asOutParam()));
            ComPtr <IHostFloppyDriveCollection> coll;
            CHECK_ERROR_BREAK (host, COMGETTER(FloppyDrives)(coll.asOutParam()));
            ComPtr <IHostFloppyDrive> hostDrive;
            rc = coll->FindByName (media, hostDrive.asOutParam());
            if (SUCCEEDED (rc))
            {
                done = true;
                CHECK_ERROR_BREAK (drive, CaptureHostDrive (hostDrive));
            }
        }

        /* Must be an image */
        if (!done)
        {
            /* try to find an existing one */
            ComPtr <IFloppyImage> image;
            rc = virtualBox->FindFloppyImage (media, image.asOutParam());
            if (FAILED (rc))
            {
                /* try to register */
                RTPrintf ("Registering floppy image '%S'...\n", fdaFile);
                Guid uuid;
                CHECK_ERROR_BREAK (virtualBox, OpenFloppyImage (media, uuid,
                                                                image.asOutParam()));
                CHECK_ERROR_BREAK (virtualBox, RegisterFloppyImage (image));
            }

            /* attach */
            Guid uuid;
            image->COMGETTER(Id)(uuid.asOutParam());
            CHECK_ERROR_BREAK (drive, MountImage (uuid));
        }
    }
    while (0);
    if (FAILED (rc))
        goto leave;

    /*
     * Mount a CD-ROM if requested.
     */
    if (cdromFile)
    do
    {
        ComPtr<IDVDDrive> drive;
        CHECK_ERROR_BREAK (gMachine, COMGETTER(DVDDrive)(drive.asOutParam()));

        /*
         * First special case 'none' to unmount
         */
        if (strcmp (cdromFile, "none") == 0)
        {
            CHECK_ERROR_BREAK (drive, Unmount());
            break;
        }

        Bstr media = cdromFile;
        bool done = false;

        /* Assume it's a host drive name */
        {
            ComPtr <IHost> host;
            CHECK_ERROR_BREAK (virtualBox, COMGETTER(Host)(host.asOutParam()));
            ComPtr <IHostDVDDriveCollection> coll;
            CHECK_ERROR_BREAK (host, COMGETTER(DVDDrives)(coll.asOutParam()));
            ComPtr <IHostDVDDrive> hostDrive;
            rc = coll->FindByName (media, hostDrive.asOutParam());
            if (SUCCEEDED (rc))
            {
                done = true;
                CHECK_ERROR_BREAK (drive, CaptureHostDrive (hostDrive));
            }
        }

        /* Must be an image */
        if (!done)
        {
            /* try to find an existing one */
            ComPtr <IDVDImage> image;
            rc = virtualBox->FindDVDImage (media, image.asOutParam());
            if (FAILED (rc))
            {
                /* try to register */
                RTPrintf ("Registering ISO image '%S'...\n", cdromFile);
                Guid uuid;
                CHECK_ERROR_BREAK (virtualBox, OpenDVDImage (media, uuid,
                                                             image.asOutParam()));
                CHECK_ERROR_BREAK (virtualBox, RegisterDVDImage (image));
            }

            /* attach */
            Guid uuid;
            image->COMGETTER(Id)(uuid.asOutParam());
            CHECK_ERROR_BREAK (drive, MountImage (uuid));
        }
    }
    while (0);
    if (FAILED (rc))
        goto leave;

    if (fDiscardState)
    {
        /*
         * If the machine is currently saved,
         * discard the saved state first.
         */
        MachineState_T machineState;
        gMachine->COMGETTER(State)(&machineState);
        if (machineState == MachineState_Saved)
        {
            CHECK_ERROR(gConsole, DiscardSavedState());
        }
        /*
         * If there are snapshots, discard the current state,
         * i.e. revert to the last snapshot.
         */
        ULONG cSnapshots;
        gMachine->COMGETTER(SnapshotCount)(&cSnapshots);
        if (cSnapshots)
        {
            gProgress = NULL;
            CHECK_ERROR(gConsole, DiscardCurrentState(gProgress.asOutParam()));
            rc = gProgress->WaitForCompletion(-1);
        }
    }

    // get the machine debugger (does not have to be there)
    gConsole->COMGETTER(Debugger)(gMachineDebugger.asOutParam());
    if (gMachineDebugger)
    {
        Log(("Machine debugger available!\n"));
    }
    gConsole->COMGETTER(Display)(gDisplay.asOutParam());
    if (!gDisplay)
    {
        RTPrintf("Error: could not get display object!\n");
        goto leave;
    }

    // set the boot drive
    if (bootDevice != DeviceType_NoDevice)
    {
        rc = gMachine->SetBootOrder(1, bootDevice);
        if (rc != S_OK)
        {
            RTPrintf("Error: could not set boot device, using default.\n");
        }
    }

    // set the memory size if not default
    if (memorySize)
    {
        rc = gMachine->COMSETTER(MemorySize)(memorySize);
        if (rc != S_OK)
        {
            ULONG ramSize = 0;
            gMachine->COMGETTER(MemorySize)(&ramSize);
            RTPrintf("Error: could not set memory size, using current setting of %d MBytes\n", ramSize);
        }
    }

    if (vramSize)
    {
        rc = gMachine->COMSETTER(VRAMSize)(vramSize);
        if (rc != S_OK)
        {
            gMachine->COMGETTER(VRAMSize)((ULONG*)&vramSize);
            RTPrintf("Error: could not set VRAM size, using current setting of %d MBytes\n", vramSize);
        }
    }

    // we're always able to process absolute mouse events and we prefer that
    gfAbsoluteMouseHost = TRUE;

#ifdef VBOX_WIN32_UI
    if (fWin32UI)
    {
        /* initialize the Win32 user interface inside which SDL will be embedded */
        if (initUI(fResizable))
            return 1;
    }
#endif

    // create our SDL framebuffer instance
    gpFrameBuffer = new VBoxSDLFB(fFullscreen, fResizable, fShowSDLConfig,
                                  fixedWidth, fixedHeight, fixedBPP);

    if (!gpFrameBuffer)
    {
        RTPrintf("Error: could not create framebuffer object!\n");
        goto leave;
    }
    if (!gpFrameBuffer->initialized())
        goto leave;
    gpFrameBuffer->AddRef();
    if (fFullscreen)
    {
        gpFrameBuffer->setFullscreen(true);
    }
#ifdef VBOX_SECURELABEL
    if (fSecureLabel)
    {
        if (!secureLabelFontFile)
        {
            RTPrintf("Error: no font file specified for secure label!\n");
            goto leave;
        }
        /* load the SDL_ttf library and get the required imports */
        int rcVBox;
        rcVBox = RTLdrLoad(LIBSDL_TTF_NAME, &gLibrarySDL_ttf);
        if (VBOX_SUCCESS(rcVBox))
            rcVBox = RTLdrGetSymbol(gLibrarySDL_ttf, "TTF_Init", (void**)&pTTF_Init);
        if (VBOX_SUCCESS(rcVBox))
            rcVBox = RTLdrGetSymbol(gLibrarySDL_ttf, "TTF_OpenFont", (void**)&pTTF_OpenFont);
        if (VBOX_SUCCESS(rcVBox))
            rcVBox = RTLdrGetSymbol(gLibrarySDL_ttf, "TTF_RenderUTF8_Solid", (void**)&pTTF_RenderUTF8_Solid);
        if (VBOX_SUCCESS(rcVBox))
            rcVBox = RTLdrGetSymbol(gLibrarySDL_ttf, "TTF_CloseFont", (void**)&pTTF_CloseFont);
        if (VBOX_SUCCESS(rcVBox))
            rcVBox = RTLdrGetSymbol(gLibrarySDL_ttf, "TTF_Quit", (void**)&pTTF_Quit);
        if (VBOX_SUCCESS(rcVBox))
            rcVBox = gpFrameBuffer->initSecureLabel(SECURE_LABEL_HEIGHT, secureLabelFontFile, secureLabelPointSize);
        if (VBOX_FAILURE(rcVBox))
        {
            RTPrintf("Error: could not initialize secure labeling: rc = %Vrc\n", rcVBox);
            goto leave;
        }
        Bstr key = VBOXSDL_SECURELABEL_EXTRADATA;
        Bstr label;
        gMachine->GetExtraData(key, label.asOutParam());
        Utf8Str labelUtf8 = label;
        /*
         * Now update the label
         */
        gpFrameBuffer->setSecureLabelColor(secureLabelColorFG, secureLabelColorBG);
        gpFrameBuffer->setSecureLabelText(labelUtf8.raw());
    }
#endif

    // register our framebuffer
    rc = gDisplay->RegisterExternalFramebuffer(gpFrameBuffer);
    if (rc != S_OK)
    {
        RTPrintf("Error: could not register framebuffer object!\n");
        goto leave;
    }

    // register a callback for global events
    callback = new VBoxSDLCallback();
    callback->AddRef();
    virtualBox->RegisterCallback(callback);

    // register a callback for machine events
    consoleCallback = new VBoxSDLConsoleCallback();
    consoleCallback->AddRef();
    gConsole->RegisterCallback(consoleCallback);
    // until we've tried to to start the VM, ignore power off events
    consoleCallback->ignorePowerOffEvents(true);

#if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN)
    /*
     * Do we have a TAP device name or file descriptor? If so, communicate
     * it to the network adapter so that it doesn't allocate a new one
     * in case TAP is already configured.
     */
    {
        ComPtr<INetworkAdapter> networkAdapter;
        for (ULONG i = 0; i < NetworkAdapterCount; i++)
        {
            if (tapdev[i] || tapfd[i])
            {
                gMachine->GetNetworkAdapter(i, networkAdapter.asOutParam());
                if (networkAdapter)
                {
                    NetworkAttachmentType_T attachmentType;
                    networkAdapter->COMGETTER(AttachmentType)(&attachmentType);
                    if (attachmentType == NetworkAttachmentType_HostInterfaceNetworkAttachment)
                    {
                        if (tapdev[i])
                            networkAdapter->COMSETTER(HostInterface)(tapdev[i]);
                        else
                            networkAdapter->COMSETTER(TAPFileDescriptor)(tapfd[i]);
                    }
                    else
                    {
                        RTPrintf("Warning: network adapter %d is not configured for TAP. Command ignored!\n", i + 1);
                    }
                }
                else
                {
                    /* warning */
                    RTPrintf("Warning: network adapter %d not defined. Command ignored!\n", i + 1);
                }
            }
        }
    }
#endif /* RT_OS_LINUX || RT_OS_DARWIN */

#ifdef VBOX_VRDP
    if (portVRDP != ~0)
    {
        rc = gMachine->COMGETTER(VRDPServer)(gVrdpServer.asOutParam());
        AssertMsg((rc == S_OK) && gVrdpServer, ("Could not get VRDP Server! rc = 0x%x\n", rc));
        if (gVrdpServer)
        {
            // has a non standard VRDP port been requested?
            if (portVRDP > 0)
            {
                rc = gVrdpServer->COMSETTER(Port)(portVRDP);
                if (rc != S_OK)
                {
                    RTPrintf("Error: could not set VRDP port! rc = 0x%x\n", rc);
                    goto leave;
                }
            }
            // now enable VRDP
            rc = gVrdpServer->COMSETTER(Enabled)(TRUE);
            if (rc != S_OK)
            {
                RTPrintf("Error: could not enable VRDP server! rc = 0x%x\n", rc);
                goto leave;
            }
        }
    }
#endif

    rc = E_FAIL;
#ifdef VBOXSDL_ADVANCED_OPTIONS
    if (fRawR0 != ~0U)
    {
        if (!gMachineDebugger)
        {
            RTPrintf("Error: No debugger object; -%srawr0 cannot be executed!\n", fRawR0 ? "" : "no");
            goto leave;
        }
        gMachineDebugger->COMSETTER(RecompileSupervisor)(!fRawR0);
    }
    if (fRawR3 != ~0U)
    {
        if (!gMachineDebugger)
        {
            RTPrintf("Error: No debugger object; -%srawr3 cannot be executed!\n", fRawR0 ? "" : "no");
            goto leave;
        }
        gMachineDebugger->COMSETTER(RecompileUser)(!fRawR3);
    }
    if (fPATM != ~0U)
    {
        if (!gMachineDebugger)
        {
            RTPrintf("Error: No debugger object; -%spatm cannot be executed!\n", fRawR0 ? "" : "no");
            goto leave;
        }
        gMachineDebugger->COMSETTER(PATMEnabled)(fPATM);
    }
    if (fCSAM != ~0U)
    {
        if (!gMachineDebugger)
        {
            RTPrintf("Error: No debugger object; -%scsam cannot be executed!\n", fRawR0 ? "" : "no");
            goto leave;
        }
        gMachineDebugger->COMSETTER(CSAMEnabled)(fCSAM);
    }
    if (fHWVirt != TriStateBool_Default)
    {
        gMachine->COMSETTER(HWVirtExEnabled)(fHWVirt);
    }
    if (u32WarpDrive != 0)
    {
        if (!gMachineDebugger)
        {
            RTPrintf("Error: No debugger object; -warpdrive %d cannot be executed!\n", u32WarpDrive);
            goto leave;
        }
        gMachineDebugger->COMSETTER(VirtualTimeRate)(u32WarpDrive);
    }
#endif /* VBOXSDL_ADVANCED_OPTIONS */

    /* start with something in the titlebar */
    UpdateTitlebar(TITLEBAR_NORMAL);

    /* memorize the default cursor */
    gpDefaultCursor = SDL_GetCursor();

#ifdef RT_OS_LINUX
    /* Get Window Manager info. We only need the X11 display. */
    SDL_VERSION(&gSdlInfo.version);
    if (!SDL_GetWMInfo(&gSdlInfo))
    {
        RTPrintf("Error: could not get SDL Window Manager info!\n");
        goto leave;
    }

    /* SDL uses its own (plain) default cursor. Use the left arrow cursor instead which might look
     * much better if a mouse cursor theme is installed. */
    gpDefaultOrigX11Cursor = *(Cursor*)gpDefaultCursor->wm_cursor;
    *(Cursor*)gpDefaultCursor->wm_cursor = XCreateFontCursor(gSdlInfo.info.x11.display, XC_left_ptr);
    SDL_SetCursor(gpDefaultCursor);
#endif /* RT_OS_LINUX */

    /* create a fake empty cursor */
    {
        uint8_t cursorData[1] = {0};
        gpCustomCursor = SDL_CreateCursor(cursorData, cursorData, 8, 1, 0, 0);
        gpCustomOrigWMcursor = gpCustomCursor->wm_cursor;
        gpCustomCursor->wm_cursor = NULL;
    }

    /*
     * Register our user signal handler.
     */
#ifdef RT_OS_LINUX
    struct sigaction sa;
    sa.sa_sigaction = signal_handler;
    sigemptyset (&sa.sa_mask);
    sa.sa_flags = SA_RESTART | SA_SIGINFO;
    sigaction (SIGUSR1, &sa, NULL);
#endif /* RT_OS_LINUX */

    /*
     * Start the VM execution thread. This has to be done
     * asynchronously as powering up can take some time
     * (accessing devices such as the host DVD drive). In
     * the meantime, we have to service the SDL event loop.
     */
    SDL_Event event;

    LogFlow(("Powering up the VM...\n"));
    rc = gConsole->PowerUp(gProgress.asOutParam());
    if (rc != S_OK)
    {
        com::ErrorInfo info(gConsole);
        if (info.isBasicAvailable())
            PrintError("Failed to power up VM", info.getText().raw());
        else
            RTPrintf("Error: failed to power up VM! No error text available.\n");
        goto leave;
    }

#ifdef USE_XPCOM_QUEUE_THREAD
    /*
     * Before we starting to do stuff, we have to launch the XPCOM
     * event queue thread. It will wait for events and send messages
     * to the SDL thread. After having done this, we should fairly
     * quickly start to process the SDL event queue as an XPCOM
     * event storm might arrive. Stupid SDL has a ridiculously small
     * event queue buffer!
     */
    startXPCOMEventQueueThread(eventQ->GetEventQueueSelectFD());
#endif /* USE_XPCOM_QUEUE_THREAD */

    /* termination flag */
    bool fTerminateDuringStartup;
    fTerminateDuringStartup = false;

    LogRel(("VBoxSDL: NUM lock initially %s, CAPS lock initially %s\n",
              !!(SDL_GetModState() & KMOD_NUM)  ? "ON" : "OFF",
              !!(SDL_GetModState() & KMOD_CAPS) ? "ON" : "OFF"));

    /* start regular timer so we don't starve in the event loop */
    SDL_TimerID sdlTimer;
    sdlTimer = SDL_AddTimer(100, StartupTimer, NULL);

    /* loop until the powerup processing is done */
    MachineState_T machineState;
    do
    {
        rc = gMachine->COMGETTER(State)(&machineState);
        if (    rc == S_OK
            &&  (   machineState == MachineState_Starting
                 || machineState == MachineState_Restoring))
        {
            /*
             * wait for the next event. This is uncritical as
             * power up guarantees to change the machine state
             * to either running or aborted and a machine state
             * change will send us an event. However, we have to
             * service the XPCOM event queue!
             */
#ifdef USE_XPCOM_QUEUE_THREAD
            if (!fXPCOMEventThreadSignaled)
            {
                signalXPCOMEventQueueThread();
                fXPCOMEventThreadSignaled = true;
            }
#endif
            /*
             * Wait for SDL events.
             */
            if (WaitSDLEvent(&event))
            {
                switch (event.type)
                {
                    /*
                     * Timer event. Used to have the titlebar updated.
                     */
                    case SDL_USER_EVENT_TIMER:
                    {
                        /*
                         * Update the title bar.
                         */
                        UpdateTitlebar(TITLEBAR_STARTUP);
                        break;
                    }

                    /*
                     * User specific resize event.
                     */
                    case SDL_USER_EVENT_RESIZE:
                    {
                        LogFlow(("SDL_USER_EVENT_RESIZE\n"));
                        gpFrameBuffer->resizeGuest();
                        /* notify the display that the resize has been completed */
                        gDisplay->ResizeCompleted(0);
                        break;
                    }

#ifdef USE_XPCOM_QUEUE_THREAD
                    /*
                     * User specific XPCOM event queue event
                     */
                    case SDL_USER_EVENT_XPCOM_EVENTQUEUE:
                    {
                        LogFlow(("SDL_USER_EVENT_XPCOM_EVENTQUEUE: processing XPCOM event queue...\n"));
                        eventQ->ProcessPendingEvents();
                        signalXPCOMEventQueueThread();
                        break;
                    }
#endif /* USE_XPCOM_QUEUE_THREAD */

                    /*
                     * Termination event from the on state change callback.
                     */
                    case SDL_USER_EVENT_TERMINATE:
                    {
                        if (event.user.code != VBOXSDL_TERM_NORMAL)
                        {
                            com::ProgressErrorInfo info(gProgress);
                            if (info.isBasicAvailable())
                                PrintError("Failed to power up VM", info.getText().raw());
                            else
                                RTPrintf("Error: failed to power up VM! No error text available.\n");
                        }
                        fTerminateDuringStartup = true;
                        break;
                    }

                    default:
                    {
                        LogBird(("VBoxSDL: Unknown SDL event %d (pre)\n", event.type));
                        break;
                    }
                }

            }
        }
    } while (   rc == S_OK
             && (   machineState == MachineState_Starting
                 || machineState == MachineState_Restoring));

    /* kill the timer again */
    SDL_RemoveTimer(sdlTimer);
    sdlTimer = 0;

    /* are we supposed to terminate the process? */
    if (fTerminateDuringStartup)
        goto leave;

    /* did the power up succeed? */
    if (machineState != MachineState_Running)
    {
        com::ProgressErrorInfo info(gProgress);
        if (info.isBasicAvailable())
            PrintError("Failed to power up VM", info.getText().raw());
        else
            RTPrintf("Error: failed to power up VM! No error text available (rc = 0x%x state = %d)\n", rc, machineState);
        goto leave;
    }

    // accept power off events from now on because we're running
    // note that there's a possible race condition here...
    consoleCallback->ignorePowerOffEvents(false);

    rc = gConsole->COMGETTER(Keyboard)(gKeyboard.asOutParam());
    if (!gKeyboard)
    {
        RTPrintf("Error: could not get keyboard object!\n");
        goto leave;
    }
    gConsole->COMGETTER(Mouse)(gMouse.asOutParam());
    if (!gMouse)
    {
        RTPrintf("Error: could not get mouse object!\n");
        goto leave;
    }

    UpdateTitlebar(TITLEBAR_NORMAL);

    /*
     * Enable keyboard repeats
     */
    SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);

    /*
     * Main event loop
     */
#ifdef USE_XPCOM_QUEUE_THREAD
    if (!fXPCOMEventThreadSignaled)
    {
        signalXPCOMEventQueueThread();
    }
#endif
    LogFlow(("VBoxSDL: Entering big event loop\n"));
    while (WaitSDLEvent(&event))
    {
        switch (event.type)
        {
            /*
             * The screen needs to be repainted.
             */
            case SDL_VIDEOEXPOSE:
            {
                /// @todo that somehow doesn't seem to work!
                gpFrameBuffer->repaint();
                break;
            }

            /*
             * Keyboard events.
             */
            case SDL_KEYDOWN:
            case SDL_KEYUP:
            {
                SDLKey ksym = event.key.keysym.sym;

                switch (enmHKeyState)
                {
                    case HKEYSTATE_NORMAL:
                    {
                        if (   event.type == SDL_KEYDOWN
                            && ksym != SDLK_UNKNOWN
                            && (ksym == gHostKeySym1 || ksym == gHostKeySym2))
                        {
                            EvHKeyDown1  = event;
                            enmHKeyState = ksym == gHostKeySym1 ? HKEYSTATE_DOWN_1ST
                                                                : HKEYSTATE_DOWN_2ND;
                            break;
                        }
                        ProcessKey(&event.key);
                        break;
                    }

                    case HKEYSTATE_DOWN_1ST:
                    case HKEYSTATE_DOWN_2ND:
                    {
                        if (gHostKeySym2 != SDLK_UNKNOWN)
                        {
                            if (   event.type == SDL_KEYDOWN
                                && ksym != SDLK_UNKNOWN
                                && (   enmHKeyState == HKEYSTATE_DOWN_1ST && ksym == gHostKeySym2
                                    || enmHKeyState == HKEYSTATE_DOWN_2ND && ksym == gHostKeySym1))
                            {
                                EvHKeyDown2  = event;
                                enmHKeyState = HKEYSTATE_DOWN;
                                break;
                            }
                            enmHKeyState = event.type == SDL_KEYUP ? HKEYSTATE_NORMAL
                                                                 : HKEYSTATE_NOT_IT;
                            ProcessKey(&EvHKeyDown1.key);
                            ProcessKey(&event.key);
                            break;
                        }
                        /* fall through if no two-key sequence is used */
                    }

                    case HKEYSTATE_DOWN:
                    {
                        if (event.type == SDL_KEYDOWN)
                        {
                            /* potential host key combination, try execute it */
                            int rc = HandleHostKey(&event.key);
                            if (rc == VINF_SUCCESS)
                            {
                                enmHKeyState = HKEYSTATE_USED;
                                break;
                            }
                            if (VBOX_SUCCESS(rc))
                                goto leave;
                        }
                        else /* SDL_KEYUP */
                        {
                            if (   ksym != SDLK_UNKNOWN
                                && (ksym == gHostKeySym1 || ksym == gHostKeySym2))
                            {
                                /* toggle grabbing state */
                                if (!gfGrabbed)
                                    InputGrabStart();
                                else
                                    InputGrabEnd();

                                /* SDL doesn't always reset the keystates, correct it */
                                ResetKeys();
                                enmHKeyState = HKEYSTATE_NORMAL;
                                break;
                            }
                        }

                        /* not host key */
                        enmHKeyState = HKEYSTATE_NOT_IT;
                        ProcessKey(&EvHKeyDown1.key);
                        if (gHostKeySym2 != SDLK_UNKNOWN)
                            ProcessKey(&EvHKeyDown2.key);
                        ProcessKey(&event.key);
                        break;
                    }

                    case HKEYSTATE_USED:
                    {
                        if ((SDL_GetModState() & ~(KMOD_MODE | KMOD_NUM | KMOD_RESERVED)) == 0)
                            enmHKeyState = HKEYSTATE_NORMAL;
                        if (event.type == SDL_KEYDOWN)
                        {
                            int rc = HandleHostKey(&event.key);
                            if (VBOX_SUCCESS(rc) && rc != VINF_SUCCESS)
                                goto leave;
                        }
                        break;
                    }

                    default:
                        AssertMsgFailed(("enmHKeyState=%d\n", enmHKeyState));
                        /* fall thru */
                    case HKEYSTATE_NOT_IT:
                    {
                        if ((SDL_GetModState() & ~(KMOD_MODE | KMOD_NUM | KMOD_RESERVED)) == 0)
                            enmHKeyState = HKEYSTATE_NORMAL;
                        ProcessKey(&event.key);
                        break;
                    }
                } /* state switch */
                break;
            }

            /*
             * The window was closed.
             */
            case SDL_QUIT:
            {
                goto leave;
                break;
            }

            /*
             * The mouse has moved
             */
            case SDL_MOUSEMOTION:
            {
                if (gfGrabbed || UseAbsoluteMouse())
                {
                    SendMouseEvent(0, 0, 0);
                }
                break;
            }

            /*
             * A mouse button has been clicked or released.
             */
            case SDL_MOUSEBUTTONDOWN:
            case SDL_MOUSEBUTTONUP:
            {
                SDL_MouseButtonEvent *bev = &event.button;
                /* don't grab on mouse click if we have guest additions */
                if (!gfGrabbed && !UseAbsoluteMouse() && gfGrabOnMouseClick)
                {
                    if (event.type == SDL_MOUSEBUTTONDOWN && (bev->state & SDL_BUTTON_LMASK))
                    {
                        /* start grabbing all events */
                        InputGrabStart();
                    }
                }
                else if (gfGrabbed || UseAbsoluteMouse())
                {
                    int dz = bev->button == SDL_BUTTON_WHEELUP
                                         ? -1
                                         : bev->button == SDL_BUTTON_WHEELDOWN
                                                       ? +1
                                                       :  0;

                    /* end host key combination (CTRL+MouseButton) */
                    switch (enmHKeyState)
                    {
                        case HKEYSTATE_DOWN_1ST:
                        case HKEYSTATE_DOWN_2ND:
                            enmHKeyState = HKEYSTATE_NOT_IT;
                            ProcessKey(&EvHKeyDown1.key);
                            break;
                        case HKEYSTATE_DOWN:
                            enmHKeyState = HKEYSTATE_NOT_IT;
                            ProcessKey(&EvHKeyDown1.key);
                            if (gHostKeySym2 != SDLK_UNKNOWN)
                                ProcessKey(&EvHKeyDown2.key);
                            break;
                        default:
                            break;
                    }

                    SendMouseEvent(dz, event.type == SDL_MOUSEBUTTONDOWN, bev->button);
                }
                break;
            }

            /*
             * The window has gained or lost focus.
             */
            case SDL_ACTIVEEVENT:
            {
                /*
                 * There is a strange behaviour in SDL when running without a window
                 * manager: When SDL_WM_GrabInput(SDL_GRAB_ON) is called we receive two
                 * consecutive events SDL_ACTIVEEVENTs (input lost, input gained).
                 * Asking SDL_GetAppState() seems the better choice.
                 */
                if (gfGrabbed && (SDL_GetAppState() & SDL_APPINPUTFOCUS) == 0)
                {
                    /*
                     * another window has stolen the (keyboard) input focus
                     */
                    InputGrabEnd();
                }
                break;
            }

            /*
             * The SDL window was resized
             */
            case SDL_VIDEORESIZE:
            {
                if (gDisplay)
                {
#ifdef VBOX_SECURELABEL
                    uResizeWidth  = event.resize.w;
                    uResizeHeight = RT_MAX(0, event.resize.h - SECURE_LABEL_HEIGHT);
#else
                    uResizeHeight = event.resize.h;
#endif
                    if (gSdlResizeTimer)
                        SDL_RemoveTimer(gSdlResizeTimer);
                    gSdlResizeTimer = SDL_AddTimer(300, ResizeTimer, NULL);
                }
                break;
            }

            /*
             * User specific update event.
             */
            /** @todo use a common user event handler so that SDL_PeepEvents() won't
             * possibly remove other events in the queue!
             */
            case SDL_USER_EVENT_UPDATERECT:
            {
                /*
                 * Decode event parameters.
                 */
                ASMAtomicDecS32(&g_cNotifyUpdateEventsPending);
                #define DECODEX(event) ((intptr_t)(event).user.data1 >> 16)
                #define DECODEY(event) ((intptr_t)(event).user.data1 & 0xFFFF)
                #define DECODEW(event) ((intptr_t)(event).user.data2 >> 16)
                #define DECODEH(event) ((intptr_t)(event).user.data2 & 0xFFFF)
                int x = DECODEX(event);
                int y = DECODEY(event);
                int w = DECODEW(event);
                int h = DECODEH(event);
                LogFlow(("SDL_USER_EVENT_UPDATERECT: x = %d, y = %d, w = %d, h = %d\n",
                        x, y, w, h));

                Assert(gpFrameBuffer);
                gpFrameBuffer->update(x, y, w, h, true /* fGuestRelative */);

                #undef DECODEX
                #undef DECODEY
                #undef DECODEW
                #undef DECODEH
                break;
            }

            /*
             * User event: Window resize done
             */
            case SDL_USER_EVENT_WINDOW_RESIZE_DONE:
            {
                /**
                 * @todo This is a workaround for synchronization problems between EMT and the
                 *       SDL main thread. It can happen that the SDL thread already starts a
                 *       new resize operation while the EMT is still busy with the old one
                 *       leading to a deadlock. Therefore we call SetVideoModeHint only once
                 *       when the mouse button was released.
                 */
                /* communicate the resize event to the guest */
                gDisplay->SetVideoModeHint(uResizeWidth, uResizeHeight, 0, 0);
                break;

            }

            /*
             * User specific resize event.
             */
            case SDL_USER_EVENT_RESIZE:
            {
                LogFlow(("SDL_USER_EVENT_RESIZE\n"));
                gpFrameBuffer->resizeGuest();
                /* notify the display that the resize has been completed */
                gDisplay->ResizeCompleted(0);
                break;
            }

#ifdef USE_XPCOM_QUEUE_THREAD
            /*
             * User specific XPCOM event queue event
             */
            case SDL_USER_EVENT_XPCOM_EVENTQUEUE:
            {
                LogFlow(("SDL_USER_EVENT_XPCOM_EVENTQUEUE: processing XPCOM event queue...\n"));
                eventQ->ProcessPendingEvents();
                signalXPCOMEventQueueThread();
                break;
            }
#endif /* USE_XPCOM_QUEUE_THREAD */

            /*
             * User specific update title bar notification event
             */
            case SDL_USER_EVENT_UPDATE_TITLEBAR:
            {
                UpdateTitlebar(TITLEBAR_NORMAL);
                break;
            }

            /*
             * User specific termination event
             */
            case SDL_USER_EVENT_TERMINATE:
            {
                if (event.user.code != VBOXSDL_TERM_NORMAL)
                    RTPrintf("Error: VM terminated abnormally!\n");
                goto leave;
            }

#ifdef VBOX_SECURELABEL
            /*
             * User specific secure label update event
             */
            case SDL_USER_EVENT_SECURELABEL_UPDATE:
            {
                /*
                 * Query the new label text
                 */
                Bstr key = VBOXSDL_SECURELABEL_EXTRADATA;
                Bstr label;
                gMachine->GetExtraData(key, label.asOutParam());
                Utf8Str labelUtf8 = label;
                /*
                 * Now update the label
                 */
                gpFrameBuffer->setSecureLabelText(labelUtf8.raw());
                break;
            }
#endif /* VBOX_SECURELABEL */

            /*
             * User specific pointer shape change event
             */
            case SDL_USER_EVENT_POINTER_CHANGE:
            {
                PointerShapeChangeData *data = (PointerShapeChangeData *) event.user.data1;
                SetPointerShape (data);
                delete data;
                break;
            }

            /*
             * User specific guest capabilities changed
             */
            case SDL_USER_EVENT_GUEST_CAP_CHANGED:
            {
                HandleGuestCapsChanged();
                break;
            }

            default:
            {
                LogBird(("unknown SDL event %d\n", event.type));
                break;
            }
        }
    }

leave:
    LogFlow(("leaving...\n"));
#if defined(VBOX_WITH_XPCOM) && !defined(RT_OS_DARWIN) && !defined(RT_OS_OS2)
    /* make sure the XPCOM event queue thread doesn't do anything harmful */
    terminateXPCOMQueueThread();
#endif /* VBOX_WITH_XPCOM */

#ifdef VBOX_VRDP
    if (gVrdpServer)
        rc = gVrdpServer->COMSETTER(Enabled)(FALSE);
#endif

    /*
     * Get the machine state.
     */
    if (gMachine)
        gMachine->COMGETTER(State)(&machineState);
    else
        machineState = MachineState_Aborted;

    /*
     * Turn off the VM if it's running
     */
    if (   gConsole
        && machineState == MachineState_Running)
    {
        consoleCallback->ignorePowerOffEvents(true);
        rc = gConsole->PowerDown();
        if (FAILED(rc))
        {
            com::ErrorInfo info;
            if (info.isFullAvailable())
                PrintError("Failed to power down VM",
                           info.getText().raw(), info.getComponent().raw());
            else
                RTPrintf("Failed to power down virtual machine! No error information available (rc = 0x%x).\n", rc);
            break;
        }
    }

    /*
     * Now we discard all settings so that our changes will
     * not be flushed to the permanent configuration
     */
    if (   gMachine
        && machineState != MachineState_Saved)
    {
        rc = gMachine->DiscardSettings();
        AssertComRC(rc);
    }

    /* close the session */
    if (sessionOpened)
    {
        rc = session->Close();
        AssertComRC(rc);
    }

    /* restore the default cursor and free the custom one if any */
    if (gpDefaultCursor)
    {
#ifdef RT_OS_LINUX
        Cursor pDefaultTempX11Cursor = *(Cursor*)gpDefaultCursor->wm_cursor;
        *(Cursor*)gpDefaultCursor->wm_cursor = gpDefaultOrigX11Cursor;
#endif /* RT_OS_LINUX */
        SDL_SetCursor(gpDefaultCursor);
#ifdef RT_OS_LINUX
        XFreeCursor(gSdlInfo.info.x11.display, pDefaultTempX11Cursor);
#endif /* RT_OS_LINUX */
    }

    if (gpCustomCursor)
    {
        WMcursor *pCustomTempWMCursor = gpCustomCursor->wm_cursor;
        gpCustomCursor->wm_cursor = gpCustomOrigWMcursor;
        SDL_FreeCursor(gpCustomCursor);
        if (pCustomTempWMCursor)
        {
#if defined (RT_OS_WINDOWS)
            ::DestroyCursor(*(HCURSOR *) pCustomTempWMCursor);
#elif defined (RT_OS_LINUX)
            XFreeCursor(gSdlInfo.info.x11.display, *(Cursor *) pCustomTempWMCursor);
#endif
            free(pCustomTempWMCursor);
        }
    }

    LogFlow(("Releasing mouse, keyboard, vrdpserver, display, console...\n"));
    if (gDisplay)
        gDisplay->SetupInternalFramebuffer(0);
    gMouse = NULL;
    gKeyboard = NULL;
    gVrdpServer = NULL;
    gDisplay = NULL;
    gConsole = NULL;
    gMachineDebugger = NULL;
    gProgress = NULL;
    // we can only uninitialize SDL here because it is not threadsafe
    if (gpFrameBuffer)
    {
        LogFlow(("Releasing framebuffer...\n"));
        gpFrameBuffer->uninit();
        gpFrameBuffer->Release();
    }
#ifdef VBOX_SECURELABEL
    /* must do this after destructing the framebuffer */
    if (gLibrarySDL_ttf)
        RTLdrClose(gLibrarySDL_ttf);
#endif
    LogFlow(("Releasing machine, session...\n"));
    gMachine = NULL;
    session = NULL;
    LogFlow(("Releasing callback handlers...\n"));
    if (callback)
        callback->Release();
    if (consoleCallback)
        consoleCallback->Release();

    LogFlow(("Releasing VirtualBox object...\n"));
    virtualBox = NULL;

    // end "all-stuff" scope
    ////////////////////////////////////////////////////////////////////////////
    }
    while (0);

    LogFlow(("Uninitializing COM...\n"));
    com::Shutdown();

    LogFlow(("Returning from main()!\n"));
    RTLogFlush(NULL);
    return FAILED (rc) ? 1 : 0;
}


Generated by  Doxygen 1.6.0   Back to index