display.cpp revision 303e983e4da980c50318ff3f84c5300e354a7ff9
/* $Id$ */
/** @file
* X11 guest client - display management.
*/
/*
* Copyright (C) 2006-2007 Sun Microsystems, Inc.
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* you can redistribute it and/or modify it under the terms of the GNU
* 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.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 USA or visit http://www.sun.com if you need
* additional information or have any questions.
*/
/** @todo this should probably be replaced by something IPRT */
/* For system() and WEXITSTATUS() */
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
#include <X11/Xlib.h>
#include <iprt/assert.h>
#include <iprt/err.h>
#include <iprt/thread.h>
#include <VBox/log.h>
#include <VBox/VMMDev.h>
#include <VBox/VBoxGuestLib.h>
#include "VBoxClient.h"
static int initDisplay()
{
int rc = VINF_SUCCESS;
int rcSystem, rcErrno;
LogFlowFunc(("\n"));
rcSystem = system("VBoxRandR --test");
if (-1 == rcSystem)
{
rcErrno = errno;
rc = RTErrConvertFromErrno(rcErrno);
}
if (RT_SUCCESS(rc))
{
if (0 != WEXITSTATUS(rcSystem))
rc = VERR_NOT_SUPPORTED;
}
if (RT_SUCCESS(rc))
rc = VbglR3CtlFilterMask( VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST
| VMMDEV_EVENT_MOUSE_CAPABILITIES_CHANGED, 0);
LogFlowFunc(("returning %Rrc\n", rc));
return rc;
}
void cleanupDisplay(void)
{
LogFlowFunc(("\n"));
VbglR3CtlFilterMask(0, VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST
| VMMDEV_EVENT_MOUSE_CAPABILITIES_CHANGED);
LogFlowFunc(("returning\n"));
}
/** This thread just runs a dummy X11 event loop to be sure that we get
* terminated should the X server exit. */
static int x11ConnectionMonitor(RTTHREAD, void *)
{
XEvent ev;
Display *pDisplay = XOpenDisplay(NULL);
while (true)
XNextEvent(pDisplay, &ev);
}
/**
* 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.
*/
int runDisplay()
{
LogFlowFunc(("\n"));
uint32_t cx0 = 0, cy0 = 0, cBits0 = 0, iDisplay0 = 0;
int rc = RTThreadCreate(NULL, x11ConnectionMonitor, NULL, 0,
RTTHREADTYPE_INFREQUENT_POLLER, 0, "X11 monitor");
if (RT_FAILURE(rc))
return rc;
VbglR3GetDisplayChangeRequest(&cx0, &cy0, &cBits0, &iDisplay0, false);
while (true)
{
uint32_t fEvents = 0, cx = 0, cy = 0, cBits = 0, iDisplay = 0;
rc = VbglR3WaitEvent(VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST,
RT_INDEFINITE_WAIT, &fEvents);
if (RT_SUCCESS(rc) && (fEvents & VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST))
{
rc = VbglR3GetDisplayChangeRequest(&cx, &cy, &cBits, &iDisplay,
true);
/* Ignore the request if it is stale */
if ((cx != cx0) || (cy != cy0) || RT_FAILURE(rc))
{
/* If we are not stopping, sleep for a bit to avoid using up
too much CPU while retrying. */
if (RT_FAILURE(rc))
RTThreadYield();
else
{
system("VBoxRandR");
cx0 = cx;
cy0 = cy;
}
}
}
}
LogFlowFunc(("returning VINF_SUCCESS\n"));
return VINF_SUCCESS;
}
class DisplayService : public VBoxClient::Service
{
public:
virtual const char *getPidFilePath()
{
return ".vboxclient-display.pid";
}
virtual int run()
{
int rc = initDisplay();
if (RT_SUCCESS(rc))
rc = runDisplay();
return rc;
}
virtual void cleanup()
{
cleanupDisplay();
}
};
VBoxClient::Service *VBoxClient::GetDisplayService()
{
return new DisplayService;
}