display.cpp revision 2acbbed6641620c958e5bdec40ed484145f59e1d
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync/* $Id$ */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync/** @file
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * X11 guest client - display management.
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync
00550544656e1a1537bad42c4f4bacef814637cavboxsync/*
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * Copyright (C) 2006-2007 Sun Microsystems, Inc.
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync *
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * available from http://www.virtualbox.org. This file is free software;
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * you can redistribute it and/or modify it under the terms of the GNU
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * General Public License (GPL) as published by the Free Software
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync *
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * Clara, CA 95054 USA or visit http://www.sun.com if you need
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * additional information or have any questions.
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync/** @todo this should probably be replaced by something IPRT */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync/* For system() and WEXITSTATUS() */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync#include <stdlib.h>
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync#include <sys/types.h>
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync#include <sys/wait.h>
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync#include <errno.h>
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync#include <X11/Xlib.h>
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync#include <X11/cursorfont.h>
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync#include <iprt/assert.h>
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync#include <iprt/err.h>
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync#include <iprt/thread.h>
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync#include <VBox/log.h>
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync#include <VBox/VMMDev.h>
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync#include <VBox/VBoxGuestLib.h>
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync#include "VBoxClient.h"
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsyncstatic int initDisplay()
101e4426c962b6d124219de44d4fd2cf2a23b178vboxsync{
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync int rc = VINF_SUCCESS;
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync int rcSystem, rcErrno;
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync uint32_t fMouseFeatures = 0;
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync LogFlowFunc(("enabling dynamic resizing\n"));
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync rcSystem = system("VBoxRandR --test");
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync if (-1 == rcSystem)
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync {
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync rcErrno = errno;
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync rc = RTErrConvertFromErrno(rcErrno);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync }
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync if (RT_SUCCESS(rc))
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync {
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync if (0 != WEXITSTATUS(rcSystem))
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync rc = VERR_NOT_SUPPORTED;
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync }
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync if (RT_SUCCESS(rc))
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync rc = VbglR3CtlFilterMask(VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST, 0);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync else
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync VbglR3CtlFilterMask(0, VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync /* Log and ignore the return value, as there is not much we can do with
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * it. */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync LogFlowFunc(("dynamic resizing: result %Rrc\n", rc));
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync /* Enable support for switching between hardware and software cursors */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync LogFlowFunc(("enabling relative mouse re-capturing support\n"));
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync rc = VbglR3GetMouseStatus(&fMouseFeatures, NULL, NULL);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync if (RT_SUCCESS(rc))
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync {
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync if (fMouseFeatures & VMMDEV_MOUSE_HOST_RECHECKS_NEEDS_HOST_CURSOR)
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync {
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync rc = VbglR3CtlFilterMask(VMMDEV_EVENT_MOUSE_CAPABILITIES_CHANGED,
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync 0);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync if (RT_SUCCESS(rc))
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync rc = VbglR3SetMouseStatus
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync ( fMouseFeatures
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync & ~VMMDEV_MOUSE_GUEST_NEEDS_HOST_CURSOR);
968c867cc19737e4e1fd97c396fcf75a3d52dd27vboxsync }
968c867cc19737e4e1fd97c396fcf75a3d52dd27vboxsync else
968c867cc19737e4e1fd97c396fcf75a3d52dd27vboxsync rc = VERR_NOT_SUPPORTED;
b84a3f2aac9529d5c5840512b12d81bc62d0e665vboxsync }
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync if (RT_FAILURE(rc))
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync {
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync VbglR3CtlFilterMask(0, VMMDEV_EVENT_MOUSE_CAPABILITIES_CHANGED);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync VbglR3SetMouseStatus( fMouseFeatures
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync | VMMDEV_MOUSE_GUEST_NEEDS_HOST_CURSOR);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync }
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync LogFlowFunc(("mouse re-capturing support: result %Rrc\n", rc));
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync return VINF_SUCCESS;
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync}
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsyncvoid cleanupDisplay(void)
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync{
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync uint32_t fMouseFeatures = 0;
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync LogFlowFunc(("\n"));
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync VbglR3CtlFilterMask(0, VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync | VMMDEV_EVENT_MOUSE_CAPABILITIES_CHANGED);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync int rc = VbglR3GetMouseStatus(&fMouseFeatures, NULL, NULL);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync if (RT_SUCCESS(rc))
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync VbglR3SetMouseStatus( fMouseFeatures
b84a3f2aac9529d5c5840512b12d81bc62d0e665vboxsync | VMMDEV_MOUSE_GUEST_NEEDS_HOST_CURSOR);
968c867cc19737e4e1fd97c396fcf75a3d52dd27vboxsync LogFlowFunc(("returning\n"));
968c867cc19737e4e1fd97c396fcf75a3d52dd27vboxsync}
b84a3f2aac9529d5c5840512b12d81bc62d0e665vboxsync
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync/** This thread just runs a dummy X11 event loop to be sure that we get
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * terminated should the X server exit. */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsyncstatic int x11ConnectionMonitor(RTTHREAD, void *)
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync{
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync XEvent ev;
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync Display *pDisplay = XOpenDisplay(NULL);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync while (true)
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync XNextEvent(pDisplay, &ev);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync return 0;
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync}
968c867cc19737e4e1fd97c396fcf75a3d52dd27vboxsync
b84a3f2aac9529d5c5840512b12d81bc62d0e665vboxsync/**
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * Display change request monitor thread function.
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * Before entering the loop, we re-read the last request
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * received, and if the first one received inside the
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * loop is identical we ignore it, because it is probably
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * stale.
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsyncint runDisplay()
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync{
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync LogFlowFunc(("\n"));
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync Display *pDisplay = XOpenDisplay(NULL);
968c867cc19737e4e1fd97c396fcf75a3d52dd27vboxsync if (pDisplay == NULL)
b84a3f2aac9529d5c5840512b12d81bc62d0e665vboxsync return VERR_NOT_FOUND;
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync Cursor hClockCursor = XCreateFontCursor(pDisplay, XC_watch);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync Cursor hArrowCursor = XCreateFontCursor(pDisplay, XC_left_ptr);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync int rc = RTThreadCreate(NULL, x11ConnectionMonitor, NULL, 0,
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync RTTHREADTYPE_INFREQUENT_POLLER, 0, "X11 monitor");
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync if (RT_FAILURE(rc))
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync return rc;
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync while (true)
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync {
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync uint32_t fEvents = 0, cx = 0, cy = 0, cBits = 0, iDisplay = 0;
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync rc = VbglR3WaitEvent( VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync | VMMDEV_EVENT_MOUSE_CAPABILITIES_CHANGED,
968c867cc19737e4e1fd97c396fcf75a3d52dd27vboxsync RT_INDEFINITE_WAIT, &fEvents);
b84a3f2aac9529d5c5840512b12d81bc62d0e665vboxsync if (RT_SUCCESS(rc) && (fEvents & VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST))
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync {
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync int rc2 = VbglR3GetDisplayChangeRequest(&cx, &cy, &cBits,
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync &iDisplay, true);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync /* If we are not stopping, sleep for a bit to avoid using up
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync too much CPU while retrying. */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync if (RT_FAILURE(rc2))
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync RTThreadYield();
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync else
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync system("VBoxRandR");
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync }
968c867cc19737e4e1fd97c396fcf75a3d52dd27vboxsync if ( RT_SUCCESS(rc)
b84a3f2aac9529d5c5840512b12d81bc62d0e665vboxsync && (fEvents & VMMDEV_EVENT_MOUSE_CAPABILITIES_CHANGED))
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync {
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync XGrabPointer(pDisplay,
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync DefaultRootWindow(pDisplay), true, 0, GrabModeAsync,
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync GrabModeAsync, None, hClockCursor, CurrentTime);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync XFlush(pDisplay);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync XGrabPointer(pDisplay,
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync DefaultRootWindow(pDisplay), true, 0, GrabModeAsync,
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync GrabModeAsync, None, hArrowCursor, CurrentTime);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync XFlush(pDisplay);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync XUngrabPointer(pDisplay, CurrentTime);
6bea637fe631bf8f14128c36c5da0fe98c0fa4edvboxsync XFlush(pDisplay);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync }
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync }
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync LogFlowFunc(("returning VINF_SUCCESS\n"));
968c867cc19737e4e1fd97c396fcf75a3d52dd27vboxsync return VINF_SUCCESS;
b84a3f2aac9529d5c5840512b12d81bc62d0e665vboxsync}
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsyncclass DisplayService : public VBoxClient::Service
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync{
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsyncpublic:
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync virtual const char *getPidFilePath()
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync {
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync return ".vboxclient-display.pid";
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync }
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync virtual int run(bool fDaemonised /* = false */)
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync {
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync int rc = initDisplay();
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync if (RT_SUCCESS(rc))
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync rc = runDisplay();
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync return rc;
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync }
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync virtual void cleanup()
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync {
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync cleanupDisplay();
968c867cc19737e4e1fd97c396fcf75a3d52dd27vboxsync }
b84a3f2aac9529d5c5840512b12d81bc62d0e665vboxsync};
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsyncVBoxClient::Service *VBoxClient::GetDisplayService()
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync{
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync return new DisplayService;
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync}
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync