getmode.c revision 23ff0a80f28ba27da3cb458face82665fe65e96c
/* $Id$ */
/** @file
* VirtualBox X11 Additions graphics driver dynamic video mode functions.
*/
/*
* Copyright (C) 2006-2014 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.
*/
#include "vboxvideo.h"
#define NEED_XF86_TYPES
#include "xf86.h"
#include "dixstruct.h"
#ifdef VBOX_GUESTR3XF86MOD
#endif
#include "extnsionst.h"
#include "windowstr.h"
#ifdef XORG_7X
# include <stdio.h>
# include <stdlib.h>
#endif
#ifdef VBOXVIDEO_13
# ifdef RT_OS_LINUX
# include "randrstr.h"
# include "xf86_OSproc.h"
# ifndef EVIOCGRAB
# endif
# ifndef KEY_SWITCHVIDEOMODE
# define KEY_SWITCHVIDEOMODE 227
# endif
# include <dirent.h>
# include <errno.h>
# include <fcntl.h>
# include <unistd.h>
# endif /* RT_OS_LINUX */
#endif /* VBOXVIDEO_13 */
/**************************************************************************
* Main functions *
**************************************************************************/
/**
* Fills a display mode M with a built-in mode of name pszName and dimensions
* cx and cy.
*/
{
char szName[256];
if (!pszName)
{
}
if (m->name)
memset(m, '\0', sizeof(*m));
m->type = M_T_BUILTIN;
/* Older versions of VBox only support screen widths which are a multiple
* of 8 */
else
}
/**
* Allocates an empty display mode and links it into the doubly linked list of
* modes pointed to by pScrn->modes. Returns a pointer to the newly allocated
* memory.
*/
{
TRACE_ENTRY();
{
}
else
{
}
return pMode;
}
/**
* Create display mode entries in the screen information structure for each
* of the graphics modes that we wish to support, that is:
* - A dynamic mode in first place which will be updated by the RandR code.
* - Any modes that the user requested in xorg.conf/XFree86Config.
*/
{
unsigned i;
/* Add two dynamic mode entries. When we receive a new size hint we will
* update whichever of these is not current. */
/* Add any modes specified by the user. We assume here that the mode names
* reflect the mode sizes. */
{
{
}
}
}
/** Set the initial values for the guest screen size hints by reading saved
* values from files. */
/** @todo Actually read the files instead of setting dummies. */
{
unsigned i;
{
}
/* Set up the first mode correctly to match the requested initial mode. */
/* RandR 1.1 quirk: make sure that the initial resolution is always present
* in the mode list as RandR will always advertise a mode of the initial
* virtual resolution via GetScreenInfo. */
}
{
pVBox->fUseHardwareCursor = true;
else
pVBox->fUseHardwareCursor = false;
}
# define SIZE_HINTS_PROPERTY "VBOX_SIZE_HINTS"
# define MOUSE_CAPABILITIES_PROPERTY "VBOX_MOUSE_CAPABILITIES"
/** Read in information about the most recent size hints requested for the
* guest screens. A client application sets the hint information as a root
* window property. */
/* TESTING: dynamic resizing and absolute pointer toggling work on old guest X servers and recent ones on Linux at the log-in screen. */
/** @note we try to maximise code coverage by typically using all code paths (HGSMI and properties) in a single X session. */
{
unsigned i;
if (vbvxGetIntegerPropery(pScrn, SIZE_HINTS_PROPERTY, &cModesFromProperty, &paModeHints) != VINF_SUCCESS)
paModeHints = NULL;
if ( vbvxGetIntegerPropery(pScrn, MOUSE_CAPABILITIES_PROPERTY, &cDummy, &pfCursorCapabilities) != VINF_SUCCESS
|| cDummy != 1)
#ifdef VBOXVIDEO_13
if (!pVBox->fHaveReadHGSMIModeHintData && RT_SUCCESS(VBoxHGSMIGetModeHints(&pVBox->guestCtx, pVBox->cScreens,
pVBox->paVBVAModeHints)))
{
{
{
/* Do not re-read this if we have data from HGSMI. */
}
}
}
if (!pVBox->fHaveReadHGSMIModeHintData)
{
if (RT_SUCCESS(VBoxQueryConfHGSMI(&pVBox->guestCtx, VBOX_VBVA_CONF32_CURSOR_CAPABILITIES, &fCursorCapabilities)))
else
pVBox->fUseHardwareCursor = false;
/* Do not re-read this if we have data from HGSMI. */
if (pfCursorCapabilities != NULL)
}
pVBox->fHaveReadHGSMIModeHintData = true;
#endif
if (paModeHints != NULL)
{
{
if (paModeHints[i] == -1)
else
{
}
}
}
if (pfCursorCapabilities != NULL && *pfCursorCapabilities != pVBox->fLastCursorCapabilitiesFromProperty)
{
}
}
{
return true;
return false;
}
static void compareAndMaybeSetUseHardwareCursor(VBOXPtr pVBox, uint32_t fCursorCapabilities, bool *pfChanged, bool fSet)
{
*pfChanged = true;
if (fSet)
}
#define SIZE_HINTS_PROPERTY "VBOX_SIZE_HINTS"
#define SIZE_HINTS_MISMATCH_PROPERTY "VBOX_SIZE_HINTS_MISMATCH"
#define MOUSE_CAPABILITIES_PROPERTY "VBOX_MOUSE_CAPABILITIES"
do { \
{ \
if (fSet) \
*(pfChanged) = true; \
} \
} while(0)
/** Read in information about the most recent size hints and cursor
* capabilities requested for the guest screens from a root window property set
* by an X11 client. Information obtained via HGSMI takes priority. */
{
int rc;
unsigned i;
bool fChanged;
bool fNeedUpdate = false;
int32_t fSizeMismatch = false;
if (vbvxGetIntegerPropery(pScrn, SIZE_HINTS_PROPERTY, &cPropertyElements, &paModeHints) != VINF_SUCCESS)
paModeHints = NULL;
if (paModeHints != NULL)
{
fChanged = false;
if (iSizeHint != 0)
{
if (iSizeHint == -1)
else
{
COMPARE_AND_MAYBE_SET(&pVBox->pScreens[i].aPreferredSize.cx, (iSizeHint >> 16) & 0x8fff, &fChanged, fNoHGSMI);
COMPARE_AND_MAYBE_SET(&pVBox->pScreens[i].aPreferredSize.cy, iSizeHint & 0x8fff, &fChanged, fNoHGSMI);
}
if (iLocation == -1)
else
{
COMPARE_AND_MAYBE_SET(&pVBox->pScreens[i].aPreferredLocation.x, (iLocation >> 16) & 0x8fff, &fChanged,
fNoHGSMI);
COMPARE_AND_MAYBE_SET(&pVBox->pScreens[i].aPreferredLocation.y, iLocation & 0x8fff, &fChanged, fNoHGSMI);
}
fNeedUpdate = true;
fSizeMismatch = true;
}
}
fChanged = false;
if ( vbvxGetIntegerPropery(pScrn, MOUSE_CAPABILITIES_PROPERTY, &cDummy, &pfCursorCapabilities) == VINF_SUCCESS
&& cDummy == 1)
compareAndMaybeSetUseHardwareCursor(pVBox, *pfCursorCapabilities, &fChanged, !pVBox->fHaveHGSMIModeHints);
fNeedUpdate = true;
fSizeMismatch = true;
*pfNeedUpdate = true;
}
/** Read in information about the most recent size hints and cursor
* capabilities requested for the guest screens from HGSMI. */
{
int rc;
unsigned i;
bool fChanged = false;
if (!pVBox->fHaveHGSMIModeHints)
return;
{
COMPARE_AND_MAYBE_SET(&pVBox->pScreens[i].aPreferredSize.cx, pVBox->paVBVAModeHints[i].cx & 0x8fff, &fChanged, true);
COMPARE_AND_MAYBE_SET(&pVBox->pScreens[i].aPreferredSize.cy, pVBox->paVBVAModeHints[i].cy & 0x8fff, &fChanged, true);
COMPARE_AND_MAYBE_SET(&pVBox->pScreens[i].afConnected, RT_BOOL(pVBox->paVBVAModeHints[i].fEnabled), &fChanged, true);
COMPARE_AND_MAYBE_SET(&pVBox->pScreens[i].aPreferredLocation.x, (int32_t)pVBox->paVBVAModeHints[i].dx & 0x8fff, &fChanged,
true);
COMPARE_AND_MAYBE_SET(&pVBox->pScreens[i].aPreferredLocation.y, (int32_t)pVBox->paVBVAModeHints[i].dy & 0x8fff, &fChanged,
true);
else
}
rc = VBoxQueryConfHGSMI(&pVBox->guestCtx, VBOX_VBVA_CONF32_CURSOR_CAPABILITIES, &fCursorCapabilities);
VBVXASSERT(rc == VINF_SUCCESS, ("Getting VBOX_VBVA_CONF32_CURSOR_CAPABILITIES failed, rc=%d.\n", rc));
*pfNeedUpdate = true;
}
#ifndef VBOXVIDEO_13
/** The RandR "proc" vector, which we wrap with our own in order to notice
* when a client sends a GetScreenInfo request. */
/** The swapped RandR "proc" vector. */
/* TESTING: dynamic resizing and toggling cursor integration work with older guest X servers (1.2 and older). */
{
return;
if (!pWin)
return;
}
{
return g_pfnVBoxRandRProc(pClient);
}
{
return g_pfnVBoxRandRSwappedProc(pClient);
}
{
return FALSE;
/* I doubt we can be loaded twice - should I fail here? */
if (g_pfnVBoxRandRProc)
return TRUE;
if (!pExt)
{
"RandR extension not found, disabling dynamic resizing.\n");
return TRUE;
}
#if !defined(XF86_VERSION_CURRENT) \
/* SwappedProcVector is not exported in XFree86, so we will not support
* swapped byte order clients. I doubt this is a big issue. */
#endif
)
FatalError("RandR \"proc\" vector not initialised\n");
#if !defined(XF86_VERSION_CURRENT) \
#endif
return TRUE;
}
/** Install our private RandR hook procedure, so that we can detect
* GetScreenInfo requests from clients to update our dynamic mode. This works
* by installing a wrapper around CreateScreenResources(), which will be called
* after RandR is initialised. The wrapper then in turn wraps the RandR "proc"
* vectors with its own handlers which will get called on any client RandR
* request. This should not be used in conjunction with RandR 1.2 or later.
* A couple of points of interest in our RandR 1.1 support:
* * We use the first two screen modes as dynamic modes. When a new mode hint
* arrives we update the first of the two which is not the current mode with
* the new size.
* * RandR 1.1 always advertises a mode of the size of the initial virtual
* resolution via GetScreenInfo(), so we make sure that a mode of that size
* is always present in the list.
* * RandR adds each new mode it sees to an internal array, but never removes
* entries. This array might end up getting rather long given that we can
* report a lot more modes than physical hardware.
*/
{
if (!pScreen->CreateScreenResources)
FatalError("called to early: CreateScreenResources not yet initialised\n");
}
#endif /* !VBOXVIDEO_13 */
#ifdef VBOXVIDEO_13
# ifdef RT_OS_LINUX
/* TESTING: dynamic resizing works on recent Linux guest X servers at the log-in screen. */
/** @note to maximise code coverage we only read data from HGSMI once, and only when responding to an ACPI event. */
{
struct input_event event;
pVBox->fHaveReadHGSMIModeHintData = false;
, TRUE
# endif
);
do
/* Why do they return EAGAIN instead of zero bytes read like everyone else does? */
}
{
int fd = -1;
FatalError("ACPI input file descriptor not initialised correctly.\n");
return;
{
{
#define BITS_PER_BLOCK (sizeof(unsigned long) * 8)
if (fd != -1)
if ( fd == -1
continue;
break;
break;
break;
fd = -1;
break;
}
}
if (fd != -1)
}
{
}
# endif /* RT_OS_LINUX */
#endif /* VBOXVIDEO_13 */