display.cpp revision 9fc58edfe4464fca24d4a064b9d3fe2ed173a71a
/* $Id$ */
/** @file
* X11 guest client - display management.
*/
/*
* Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*/
/** @todo this should probably be replaced by something IPRT */
/* For system() and WEXITSTATUS() */
#include <stdlib.h>
#include <errno.h>
#include <X11/cursorfont.h>
#include <VBox/VBoxGuestLib.h>
#include "VBoxClient.h"
/** State information we need for interacting with the X server. */
struct x11State
{
/** The connection to the server. */
/** Can we use version 1.2 or later of the RandR protocol here? */
bool fHaveRandR12;
/** The command argument to use for the xrandr binary. Currently only
* used to support the non-standard location on some Solaris systems -
* would it make sense to use absolute paths on all systems? */
const char *pcszXrandr;
/** The size of our array of size hints. */
unsigned cSizeHints;
/** Array of size hints. Large enough to hold the highest display
* number we have had a hint for so far, reallocated when a higher one
* comes. Zero means no hint for that display. */
long *paSizeHints;
};
/** Tell the VBoxGuest driver we no longer want any events and tell the host
* we no longer support any capabilities. */
static int disableEventsAndCaps()
{
if (RT_FAILURE(rc))
if (RT_FAILURE(rc))
if (RT_FAILURE(rc))
return VINF_SUCCESS;
}
/** Tell the VBoxGuest driver which events we want and tell the host which
* capabilities we support. */
static int enableEventsAndCaps()
{
if (RT_FAILURE(rc))
if (RT_FAILURE(rc))
rc = VbglR3SetMouseStatus(0);
if (RT_FAILURE(rc))
return VINF_SUCCESS;
}
{
char szCommand[256];
int status;
return VERR_NOT_FOUND;
pState->fHaveRandR12 = false;
if (RTFileExists("/usr/X11/bin/xrandr"))
VBClFatalError(("Failed to execute the xrandr utility.\n"));
if (WEXITSTATUS(status) == 0)
pState->fHaveRandR12 = true;
pState->cSizeHints = 0;
return VINF_SUCCESS;
}
unsigned y, bool fEnabled, bool fChangeOrigin)
{
char szCommand[256];
int status;
uint32_t i;
{
(iDisplay + 1)
* sizeof(*pState->paSizeHints));
if (!pState->paSizeHints)
VBClFatalError(("Failed to re-allocate size hint memory.\n"));
pState->paSizeHints[i] = 0;
}
{
(unsigned char *)pState->paSizeHints,
pState->cSizeHints);
}
if (!pState->fHaveRandR12)
{
if (WEXITSTATUS(status) != 0)
}
else
{
if (fChangeOrigin && fEnabled)
{
/* Extended Display support possible . Secondary monitor
* position supported */
"%s --output VGA-%u --auto --pos %ux%u",
if (WEXITSTATUS(status) != 0)
}
{
"%s --output VGA-%u --preferred",
if (WEXITSTATUS(status) != 0)
}
if (!fEnabled)
{
/* disable the virtual monitor */
"%s --output VGA-%u --off",
if (WEXITSTATUS(status) != 0)
}
}
}
/**
* Display change request monitor thread function.
* Before entering the loop, we re-read the last request
* received, and if the first one received inside the
* loop is identical we ignore it, because it is probably
* stale.
*/
{
unsigned i, cScreens;
char szCommand[256];
LogRelFlowFunc(("\n"));
if (RT_FAILURE(rc))
VBClFatalError(("Failed to get the number of saved screen modes, rc=%Rrc\n",
rc));
{
bool fEnabled = true;
&fEnabled);
VBClFatalError(("Internal error retrieving the number of saved screen modes.\n"));
if (RT_SUCCESS(rc))
true);
}
while (true)
{
do
while(rc == VERR_INTERRUPTED);
{
/* Jiggle the mouse pointer to trigger a switch to a software
* cursor if necessary. */
}
/* And if it is a size hint, set the new size. */
{
bool fEnabled = true, fChangeOrigin = true;
&x, &y, &fEnabled,
&fChangeOrigin, true);
/* Extended display version not supported on host */
if (RT_FAILURE(rc))
VBClFatalError(("Failed to get display change request, rc=%Rrc\n",
rc));
else
LogRelFlowFunc(("Got extended size hint from host cx=%d, cy=%d, bpp=%d, iDisplay=%d, x=%d, y=%d fEnabled=%d\n",
fEnabled));
if (RT_FAILURE(rc))
VBClFatalError(("Received a size hint for too high display number %u\n",
(unsigned) iDisplay));
if (RT_FAILURE(rc))
if (Mode == VMMDev_Seamless_Disabled)
{
fEnabled);
if ( RT_FAILURE(rc)
}
}
}
}
/** Display magic number, start of a UUID. */
#define DISPLAYSERVICE_MAGIC 0xf0029993
/** VBoxClient service class wrapping the logic for the display service while
* the main VBoxClient code provides the daemon logic needed by all services.
*/
struct DISPLAYSERVICE
{
/** The service interface. */
struct VBCLSERVICE *pInterface;
/** Magic number for sanity checks. */
/** State related to the X server. */
/** Are we initialised yet? */
bool mfInit;
};
static const char *getPidFilePath()
{
return ".vboxclient-display.pid";
}
{
VBClFatalError(("Bad display service object!\n"));
return pSelf;
}
{
int rc;
return VERR_WRONG_ORDER;
if (RT_FAILURE(rc))
return rc;
rc = enableEventsAndCaps();
if (RT_SUCCESS(rc))
return rc;
}
{
int rc;
return VERR_WRONG_ORDER;
rc = VBClStartVTMonitor();
if (RT_FAILURE(rc))
return VERR_INTERNAL_ERROR; /* "Should never reach here." */
}
{
return VERR_WRONG_ORDER;
return disableEventsAndCaps();
}
{
return VERR_WRONG_ORDER;
return enableEventsAndCaps();
}
{
}
struct VBCLSERVICE vbclDisplayInterface =
{
init,
run,
};
struct VBCLSERVICE **VBClGetDisplayService()
{
struct DISPLAYSERVICE *pService =
if (!pService)
VBClFatalError(("Out of memory\n"));
return &pService->pInterface;
}