summaryrefslogtreecommitdiffstats
path: root/src/VBox/Frontends/VBoxFB
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 14:19:18 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 14:19:18 +0000
commit4035b1bfb1e5843a539a8b624d21952b756974d1 (patch)
treef1e9cd5bf548cbc57ff2fddfb2b4aa9ae95587e2 /src/VBox/Frontends/VBoxFB
parentInitial commit. (diff)
downloadvirtualbox-4035b1bfb1e5843a539a8b624d21952b756974d1.tar.xz
virtualbox-4035b1bfb1e5843a539a8b624d21952b756974d1.zip
Adding upstream version 6.1.22-dfsg.upstream/6.1.22-dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/VBox/Frontends/VBoxFB')
-rw-r--r--src/VBox/Frontends/VBoxFB/Framebuffer.cpp373
-rw-r--r--src/VBox/Frontends/VBoxFB/Framebuffer.h74
-rw-r--r--src/VBox/Frontends/VBoxFB/Helper.cpp98
-rw-r--r--src/VBox/Frontends/VBoxFB/Helper.h39
-rw-r--r--src/VBox/Frontends/VBoxFB/Makefile.kmk42
-rw-r--r--src/VBox/Frontends/VBoxFB/VBoxFB.cpp577
-rw-r--r--src/VBox/Frontends/VBoxFB/VBoxFB.h81
7 files changed, 1284 insertions, 0 deletions
diff --git a/src/VBox/Frontends/VBoxFB/Framebuffer.cpp b/src/VBox/Frontends/VBoxFB/Framebuffer.cpp
new file mode 100644
index 00000000..f743cac5
--- /dev/null
+++ b/src/VBox/Frontends/VBoxFB/Framebuffer.cpp
@@ -0,0 +1,373 @@
+/* $Id: Framebuffer.cpp $ */
+/** @file
+ * VBoxFB - implementation of VBoxDirectFB class.
+ */
+
+/*
+ * Copyright (C) 2006-2020 Oracle Corporation
+ *
+ * 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.
+ */
+
+#include "VBoxFB.h"
+#include "Framebuffer.h"
+
+NS_IMPL_ISUPPORTS1_CI(VBoxDirectFB, IFramebuffer)
+NS_DECL_CLASSINFO(VBoxDirectFB)
+
+VBoxDirectFB::VBoxDirectFB(IDirectFB *aDFB, IDirectFBSurface *aSurface)
+{
+ dfb = aDFB;
+ surface = aSurface;
+ fbInternalSurface = NULL;
+ fbBufferAddress = NULL;
+ // initialize screen dimensions
+ DFBCHECK(surface->GetSize(surface, (int*)&screenWidth, (int*)&screenHeight));
+ fbWidth = 640;
+ fbHeight = 480;
+ if ((screenWidth != fbWidth) || (screenHeight != fbHeight))
+ {
+ createSurface(fbWidth, fbHeight);
+ }
+ fbSurfaceLocked = 0;
+ PRUint32 bitsPerPixel;
+ GetBitsPerPixel(&bitsPerPixel);
+ fbPitch = fbWidth * (bitsPerPixel / 8);
+}
+
+VBoxDirectFB::~VBoxDirectFB()
+{
+ // free our internal surface
+ if (fbInternalSurface)
+ {
+ DFBCHECK(fbInternalSurface->Release(fbInternalSurface));
+ fbInternalSurface = NULL;
+ }
+}
+
+NS_IMETHODIMP VBoxDirectFB::GetWidth(uint32 *width)
+{
+ if (!width)
+ return NS_ERROR_INVALID_POINTER;
+ *width = fbWidth;
+ return NS_OK;
+}
+
+NS_IMETHODIMP VBoxDirectFB::GetHeight(PRUint32 *height)
+{
+ if (!height)
+ return NS_ERROR_INVALID_POINTER;
+ *height = fbHeight;
+ return NS_OK;
+}
+
+NS_IMETHODIMP VBoxDirectFB::Lock()
+{
+ // do we have an internal framebuffer?
+ if (fbInternalSurface)
+ {
+ if (fbSurfaceLocked)
+ {
+ printf("internal surface already locked!\n");
+ } else
+ {
+ DFBCHECK(fbInternalSurface->Lock(fbInternalSurface,
+ (DFBSurfaceLockFlags)(DSLF_WRITE | DSLF_READ),
+ &fbBufferAddress, (int*)&fbPitch));
+ fbSurfaceLocked = 1;
+ }
+ } else
+ {
+ if (fbSurfaceLocked)
+ {
+ printf("surface already locked!\n");
+ } else
+ {
+ DFBCHECK(surface->Lock(surface, (DFBSurfaceLockFlags)(DSLF_WRITE | DSLF_READ),
+ &fbBufferAddress, (int*)&fbPitch));
+ fbSurfaceLocked = 1;
+ }
+ }
+ return NS_OK;
+}
+
+NS_IMETHODIMP VBoxDirectFB::Unlock()
+{
+ // do we have an internal framebuffer?
+ if (fbInternalSurface)
+ {
+ if (!fbSurfaceLocked)
+ {
+ printf("internal surface not locked!\n");
+ } else
+ {
+ DFBCHECK(fbInternalSurface->Unlock(fbInternalSurface));
+ fbSurfaceLocked = 0;
+ }
+ } else
+ {
+ if (!fbSurfaceLocked)
+ {
+ printf("surface not locked!\n");
+ } else
+ {
+ DFBCHECK(surface->Unlock(surface));
+ fbSurfaceLocked = 0;
+ }
+ }
+ return NS_OK;
+}
+
+NS_IMETHODIMP VBoxDirectFB::GetAddress(PRUint8 **address)
+{
+ if (!address)
+ return NS_ERROR_INVALID_POINTER;
+ *address = (PRUint8 *)fbBufferAddress;
+ return NS_OK;
+}
+
+NS_IMETHODIMP VBoxDirectFB::GetBitsPerPixel(PRUint32 *bitsPerPixel)
+{
+ if (!bitsPerPixel)
+ return NS_ERROR_INVALID_POINTER;
+ DFBSurfacePixelFormat pixelFormat;
+ DFBCHECK(surface->GetPixelFormat(surface, &pixelFormat));
+ switch (pixelFormat)
+ {
+ case DSPF_RGB16:
+ *bitsPerPixel = 16;
+ break;
+ case DSPF_RGB24:
+ *bitsPerPixel = 24;
+ break;
+ case DSPF_RGB32:
+ *bitsPerPixel = 32;
+ break;
+ default:
+ // not good! @@@AH do something!
+ *bitsPerPixel = 16;
+ }
+ return NS_OK;
+}
+
+NS_IMETHODIMP VBoxDirectFB::GetBytesPerLine(PRUint32 *bytesPerLine)
+{
+ if (!bytesPerLine)
+ return NS_ERROR_INVALID_POINTER;
+ *bytesPerLine = fbPitch;
+ return NS_OK;
+}
+
+NS_IMETHODIMP VBoxDirectFB::GetPixelFormat (PRUint32 *pixelFormat)
+{
+ if (!pixelFormat)
+ return NS_ERROR_INVALID_POINTER;
+ *pixelFormat = FramebufferPixelFormat_FOURCC_RGB;
+ return NS_OK;
+}
+
+NS_IMETHODIMP VBoxDirectFB::GetUsesGuestVRAM (PRBool *usesGuestVRAM)
+{
+ if (!usesGuestVRAM)
+ return NS_ERROR_INVALID_POINTER;
+ *usesGuestVRAM = false;
+ return NS_OK;
+}
+
+NS_IMETHODIMP VBoxDirectFB::GetHeightReduction(PRUint32 *heightReduction)
+{
+ if (!heightReduction)
+ return NS_ERROR_INVALID_POINTER;
+ *heightReduction = 0;
+ return NS_OK;
+}
+
+NS_IMETHODIMP VBoxDirectFB::GetOverlay(IFramebufferOverlay **overlay)
+{
+ if (!overlay)
+ return NS_ERROR_INVALID_POINTER;
+ /* Not yet implemented */
+ *overlay = 0;
+ return NS_OK;
+}
+
+NS_IMETHODIMP VBoxDirectFB::GetWinId(PRint64 *winId)
+{
+ if (!winId)
+ return NS_ERROR_INVALID_POINTER;
+ *winId = 0;
+ return NS_OK;
+}
+
+NS_IMETHODIMP VBoxDirectFB::NotifyUpdate(PRUint32 x, PRUint32 y,
+ PRUint32 w, PRUint32 h)
+{
+ // we only need to take action if we have a memory framebuffer
+ if (fbInternalSurface)
+ {
+ //printf("blitting %u %u %u %u...\n", x, y, w, h);
+ DFBRectangle blitRectangle;
+ blitRectangle.x = x;
+ blitRectangle.y = y;
+ blitRectangle.w = w;
+ blitRectangle.h = h;
+ if (scaleGuest)
+ {
+ DFBRectangle hostRectangle;
+ float factorX = (float)screenWidth / (float)fbWidth;
+ float factorY = (float)screenHeight / (float)fbHeight;
+ hostRectangle.x = (int)((float)blitRectangle.x * factorX);
+ hostRectangle.y = (int)((float)blitRectangle.y * factorY);
+ hostRectangle.w = (int)((float)blitRectangle.w * factorX);
+ hostRectangle.h = (int)((float)blitRectangle.h * factorY);
+ DFBCHECK(surface->StretchBlit(surface, fbInternalSurface,
+ &blitRectangle, &hostRectangle));
+ }
+ else
+ {
+ DFBCHECK(surface->Blit(surface, fbInternalSurface, &blitRectangle,
+ x + ((screenWidth - fbWidth) / 2),
+ y + (screenHeight - fbHeight) / 2));
+ }
+ }
+ return NS_OK;
+}
+
+NS_IMETHODIMP VBoxDirectFB::RequestResize(PRUint32 aScreenId, PRUint32 pixelFormat, PRUint8 *vram,
+ PRUint32 bitsPerPixel, PRUint32 bytesPerLine,
+ PRUint32 w, PRUint32 h,
+ PRBool *finished)
+{
+ uint32_t needsLocking = fbSurfaceLocked;
+
+ printf("RequestResize: aScreenId = %d, pixelFormat = %d, vram = %p, bitsPerPixel = %d, bytesPerLine = %d, w = %d, h = %d, fbSurfaceLocked = %d\n", aScreenId, pixelFormat, vram, bitsPerPixel, bytesPerLine, w, h, fbSurfaceLocked);
+
+ // we can't work with a locked surface
+ if (needsLocking)
+ {
+ Unlock();
+ }
+
+ // in any case we gotta free a possible internal framebuffer
+ if (fbInternalSurface)
+ {
+ printf("freeing internal surface\n");
+ fbInternalSurface->Release(fbInternalSurface);
+ fbInternalSurface = NULL;
+ }
+
+ // check if we have a fixed host video mode
+ if (useFixedVideoMode)
+ {
+ // does the current video mode differ from what the guest wants?
+ if ((screenWidth == w) && (screenHeight == h))
+ {
+ printf("requested guest mode matches current host mode!\n");
+ } else
+ {
+ createSurface(w, h);
+ }
+ } else
+ {
+ // we adopt to the guest resolution or the next higher that is available
+ int32_t bestMode = getBestVideoMode(w, h, bitsPerPixel);
+ if (bestMode == -1)
+ {
+ // oh oh oh oh
+ printf("RequestResize: no suitable mode found!\n");
+ return NS_OK;
+ }
+
+ // does the mode differ from what we wanted?
+ if ((videoModes[bestMode].width != w) || (videoModes[bestMode].height != h) ||
+ (videoModes[bestMode].bpp != bitsPerPixel))
+ {
+ printf("The mode does not fit exactly!\n");
+ createSurface(w, h);
+ } else
+ {
+ printf("The mode fits exactly!\n");
+ }
+ // switch to this mode
+ DFBCHECK(dfb->SetVideoMode(dfb, videoModes[bestMode].width, videoModes[bestMode].height,
+ videoModes[bestMode].bpp));
+ }
+
+ // update dimensions to the new size
+ fbWidth = w;
+ fbHeight = h;
+
+ // clear the screen
+ DFBCHECK(surface->Clear(surface, 0, 0, 0, 0));
+
+ // if it was locked before the resize, obtain the lock again
+ if (needsLocking)
+ {
+ Lock();
+ }
+
+ if (finished)
+ *finished = true;
+ return NS_OK;
+}
+
+NS_IMETHODIMP VBoxDirectFB::VideoModeSupported(PRUint32 w, PRUint32 h, PRUint32 bpp, PRBool *supported)
+{
+ if (!supported)
+ return NS_ERROR_INVALID_POINTER;
+ *supported = true;
+ return NS_OK;
+}
+
+NS_IMETHODIMP VBoxDirectFB::GetVisibleRegion(PRUint8 *rectangles, PRUint32 count, PRUint32 *countCopied)
+{
+ PRTRECT rects = (PRTRECT)rectangles;
+
+ if (!rects || !countCopied)
+ return NS_ERROR_INVALID_POINTER;
+ /** @todo */
+ *countCopied = 0;
+ return NS_OK;
+}
+
+NS_IMETHODIMP VBoxDirectFB::SetVisibleRegion(PRUint8 *rectangles, PRUint32 count)
+{
+ PRTRECT rects = (PRTRECT)rectangles;
+
+ if (!rects)
+ return NS_ERROR_INVALID_POINTER;
+ /** @todo */
+ return NS_OK;
+}
+
+NS_IMETHODIMP VBoxDirectFB::ProcessVHWACommand(PRUint8 *command, LONG enmCmd, BOOL fGuestCmd)
+{
+ RT_NOREF(command, enmCmd, fGuestCmd);
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP VBoxDirectFB::Notify3DEvent(PRUint32 type, PRUint8 *reserved)
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+int VBoxDirectFB::createSurface(uint32_t w, uint32_t h)
+{
+ printf("creating a new internal surface, w = %u, h = %u...\n", w, h);
+ // create a surface
+ DFBSurfaceDescription dsc;
+ DFBSurfacePixelFormat pixelFormat;
+ dsc.flags = (DFBSurfaceDescriptionFlags)(DSDESC_WIDTH | DSDESC_HEIGHT | DSDESC_PIXELFORMAT);
+ dsc.width = w;
+ dsc.height = h;
+ DFBCHECK(surface->GetPixelFormat(surface, &pixelFormat));
+ dsc.pixelformat = pixelFormat;
+ DFBCHECK(dfb->CreateSurface(dfb, &dsc, &fbInternalSurface));
+ return 0;
+}
diff --git a/src/VBox/Frontends/VBoxFB/Framebuffer.h b/src/VBox/Frontends/VBoxFB/Framebuffer.h
new file mode 100644
index 00000000..55637be8
--- /dev/null
+++ b/src/VBox/Frontends/VBoxFB/Framebuffer.h
@@ -0,0 +1,74 @@
+/** @file
+ * VBoxFB - Declaration of VBoxDirectFB class.
+ */
+
+/*
+ * Copyright (C) 2006-2020 Oracle Corporation
+ *
+ * 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.
+ */
+
+#ifndef VBOX_INCLUDED_SRC_VBoxFB_Framebuffer_h
+#define VBOX_INCLUDED_SRC_VBoxFB_Framebuffer_h
+#ifndef RT_WITHOUT_PRAGMA_ONCE
+# pragma once
+#endif
+
+#include "VBoxFB.h"
+
+class VBoxDirectFB : public IFramebuffer
+{
+public:
+ VBoxDirectFB(IDirectFB *aDFB, IDirectFBSurface *aSurface);
+ virtual ~VBoxDirectFB();
+
+ NS_DECL_ISUPPORTS
+
+ NS_IMETHOD GetWidth(PRUint32 *width);
+ NS_IMETHOD GetHeight(PRUint32 *height);
+ NS_IMETHOD Lock();
+ NS_IMETHOD Unlock();
+ NS_IMETHOD GetAddress(PRUint8 **address);
+ NS_IMETHOD GetBitsPerPixel(PRUint32 *bitsPerPixel);
+ NS_IMETHOD GetBytesPerLine(PRUint32 *bytesPerLine);
+ NS_IMETHOD GetPixelFormat(PRUint32 *pixelFormat);
+ NS_IMETHOD GetUsesGuestVRAM(PRBool *usesGuestVRAM);
+ NS_IMETHOD GetHeightReduction(PRUint32 *heightReduction);
+ NS_IMETHOD GetOverlay(IFramebufferOverlay **aOverlay);
+ NS_IMETHOD GetWinId(PRUint64 *winId);
+ NS_IMETHOD NotifyUpdate(PRUint32 x, PRUint32 y, PRUint32 w, PRUint32 h);
+ NS_IMETHOD RequestResize(PRUint32 aScreenId, PRUint32 pixelFormat, PRUint8 *vram,
+ PRUint32 bitsPerPixel, PRUint32 bytesPerLine,
+ PRUint32 w, PRUint32 h,
+ PRBool *finished);
+ NS_IMETHOD VideoModeSupported(PRUint32 width, PRUint32 height, PRUint32 bpp, PRBool *supported);
+ NS_IMETHOD GetVisibleRegion(PRUint8 *aRectangles, PRUint32 aCount, PRUint32 *aCountCopied);
+ NS_IMETHOD SetVisibleRegion(PRUint8 *aRectangles, PRUint32 aCount);
+
+ NS_IMETHOD ProcessVHWACommand(PRUint8 *pCommand, LONG enmCmd, BOOL fGuestCmd);
+
+ NS_IMETHOD Notify3DEvent(PRUint32 type, PRUint8 *reserved);
+private:
+ int createSurface(uint32_t w, uint32_t h);
+
+ IDirectFB *dfb;
+ IDirectFBSurface *surface;
+ uint32_t screenWidth;
+ uint32_t screenHeight;
+ IDirectFBSurface *fbInternalSurface;
+ void *fbBufferAddress;
+ uint32_t fbWidth;
+ uint32_t fbHeight;
+ uint32_t fbPitch;
+ int fbSurfaceLocked;
+};
+
+
+#endif /* !VBOX_INCLUDED_SRC_VBoxFB_Framebuffer_h */
+
diff --git a/src/VBox/Frontends/VBoxFB/Helper.cpp b/src/VBox/Frontends/VBoxFB/Helper.cpp
new file mode 100644
index 00000000..35f0e55a
--- /dev/null
+++ b/src/VBox/Frontends/VBoxFB/Helper.cpp
@@ -0,0 +1,98 @@
+/** @file
+ *
+ * VBox frontends: Framebuffer (FB, DirectFB):
+ * Helper routines
+ */
+
+/*
+ * Copyright (C) 2006-2020 Oracle Corporation
+ *
+ * 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.
+ */
+
+#include "VBoxFB.h"
+#include "Helper.h"
+
+/**
+ * Globals
+ */
+videoMode videoModes[MAX_VIDEOMODES] = {{0}};
+uint32_t numVideoModes = 0;
+
+/**
+ * callback handler for populating the supported video modes
+ *
+ * @returns callback success indicator
+ * @param width width in pixels of the current video mode
+ * @param height height in pixels of the current video mode
+ * @param bpp bits per pixel of the current video mode
+ * @param callbackdata user data pointer
+ */
+DFBEnumerationResult enumVideoModesHandler(int width, int height, int bpp, void *callbackdata)
+{
+ if (numVideoModes >= MAX_VIDEOMODES)
+ {
+ return DFENUM_CANCEL;
+ }
+ // don't take palette based modes
+ if (bpp >= 16)
+ {
+ // don't take modes we already have (I have seen many cases where
+ // DirectFB returns the same modes several times)
+ int32_t existingMode = getBestVideoMode(width, height, bpp);
+ if ((existingMode == -1) ||
+ ((videoModes[existingMode].width != (uint32_t)width) ||
+ (videoModes[existingMode].height != (uint32_t)height) ||
+ (videoModes[existingMode].bpp != (uint32_t)bpp)))
+ {
+ videoModes[numVideoModes].width = (uint32_t)width;
+ videoModes[numVideoModes].height = (uint32_t)height;
+ videoModes[numVideoModes].bpp = (uint32_t)bpp;
+ numVideoModes++;
+ }
+ }
+ return DFENUM_OK;
+}
+
+/**
+ * Returns the best fitting video mode for the given characteristics.
+ *
+ * @returns index of the best video mode, -1 if no suitable mode found
+ * @param width requested width
+ * @param height requested height
+ * @param bpp requested bit depth
+ */
+int32_t getBestVideoMode(uint32_t width, uint32_t height, uint32_t bpp)
+{
+ int32_t bestMode = -1;
+
+ for (uint32_t i = 0; i < numVideoModes; i++)
+ {
+ // is this mode compatible?
+ if ((videoModes[i].width >= width) && (videoModes[i].height >= height) &&
+ (videoModes[i].bpp >= bpp))
+ {
+ // first suitable mode?
+ if (bestMode == -1)
+ {
+ bestMode = i;
+ } else
+ {
+ // is it better than the one we got before?
+ if ((videoModes[i].width < videoModes[bestMode].width) ||
+ (videoModes[i].height < videoModes[bestMode].height) ||
+ (videoModes[i].bpp < videoModes[bestMode].bpp))
+ {
+ bestMode = i;
+ }
+ }
+ }
+ }
+ return bestMode;
+}
diff --git a/src/VBox/Frontends/VBoxFB/Helper.h b/src/VBox/Frontends/VBoxFB/Helper.h
new file mode 100644
index 00000000..282f0c6d
--- /dev/null
+++ b/src/VBox/Frontends/VBoxFB/Helper.h
@@ -0,0 +1,39 @@
+/** @file
+ *
+ * VBox frontends: Framebuffer (FB, DirectFB):
+ * Helper routines
+ */
+
+/*
+ * Copyright (C) 2006-2020 Oracle Corporation
+ *
+ * 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.
+ */
+
+#ifndef VBOX_INCLUDED_SRC_VBoxFB_Helper_h
+#define VBOX_INCLUDED_SRC_VBoxFB_Helper_h
+#ifndef RT_WITHOUT_PRAGMA_ONCE
+# pragma once
+#endif
+
+#define MAX_VIDEOMODES 64
+struct videoMode
+{
+ uint32_t width;
+ uint32_t height;
+ uint32_t bpp;
+};
+extern videoMode videoModes[];
+extern uint32_t numVideoModes;
+
+DFBEnumerationResult enumVideoModesHandler(int width, int height, int bpp, void *callbackdata);
+int32_t getBestVideoMode(uint32_t width, uint32_t height, uint32_t bpp);
+
+
+#endif /* !VBOX_INCLUDED_SRC_VBoxFB_Helper_h */
diff --git a/src/VBox/Frontends/VBoxFB/Makefile.kmk b/src/VBox/Frontends/VBoxFB/Makefile.kmk
new file mode 100644
index 00000000..76d80eba
--- /dev/null
+++ b/src/VBox/Frontends/VBoxFB/Makefile.kmk
@@ -0,0 +1,42 @@
+# $Id: Makefile.kmk $
+## @file
+# Sub-Makefile for VBoxFB.
+#
+
+#
+# Copyright (C) 2006-2020 Oracle Corporation
+#
+# 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.
+#
+
+SUB_DEPTH = ../../../..
+include $(KBUILD_PATH)/subheader.kmk
+
+PROGRAMS += VBoxFB
+
+#
+# VBoxFB
+#
+VBoxFB_TEMPLATE = VBOXR3NPEXE
+VBoxFB_SOURCES = \
+ VBoxFB.cpp \
+ Framebuffer.cpp \
+ Helper.cpp
+VBoxFB_CXXFLAGS = -Wno-non-virtual-dtor -fshort-wchar
+ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP
+ VBoxFB_DEFS += VBOX_WITH_XPCOM_NAMESPACE_CLEANUP
+endif
+VBoxFB_INCS = $(VBOX_XPCOM_INCS) /usr/include/directfb
+VBoxFB_LIBPATH = $(LIBPATH_XPCOM)
+VBoxFB_LIBS = $(LIB_XPCOM) $(LIB_RUNTIME) directfb
+VBoxFB_DEPS = $(VBOX_PATH_SDK)/bindings/xpcom/include/VirtualBox_XPCOM.h
+
+# generate rules.
+include $(FILE_KBUILD_SUB_FOOTER)
+
diff --git a/src/VBox/Frontends/VBoxFB/VBoxFB.cpp b/src/VBox/Frontends/VBoxFB/VBoxFB.cpp
new file mode 100644
index 00000000..483de59d
--- /dev/null
+++ b/src/VBox/Frontends/VBoxFB/VBoxFB.cpp
@@ -0,0 +1,577 @@
+/** @file
+ *
+ * VBox frontends: Framebuffer (FB, DirectFB):
+ * main() routine.
+ *
+ * NOTE: this code has not been tested, so expect bugs. It is not part
+ * of a regular VirtualBox build.
+ */
+
+/*
+ * Copyright (C) 2006-2020 Oracle Corporation
+ *
+ * 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.
+ */
+
+#include "VBoxFB.h"
+#include "Framebuffer.h"
+#include <getopt.h>
+#include <VBox/param.h>
+#include <iprt/path.h>
+
+/**
+ * Globals
+ */
+uint32_t useFixedVideoMode = 0;
+int scaleGuest = 0;
+videoMode fixedVideoMode = {0};
+int32_t initialVideoMode = -1;
+
+void showusage()
+{
+ printf("\nThe following parameters are supported:\n"
+ "--startvm uuid start VM with UUID 'uuid'\n"
+ "--fixedres WxHxBPP always use fixed host resolution\n"
+ "--listhostmodes display list of supported host display modes and exit\n"
+ "--scale scale guest video mode to host video mode\n"
+ "--nodirectblit disable direct blitting, use intermediate framebuffer\n"
+ "--showlabel show VM name on top of the VM display\n");
+}
+
+/** entry point */
+int main(int argc, char *argv[])
+{
+ const char *uuid = NULL;
+ int c;
+ int listHostModes = 0;
+ int quit = 0;
+ const struct option options[] =
+ {
+ { "help", no_argument, NULL, 'h' },
+ { "startvm", required_argument, NULL, 's' },
+ { "fixedres", required_argument, NULL, 'f' },
+ { "listhostmodes", no_argument, NULL, 'l' },
+ { "scale", no_argument, NULL, 'c' }
+ };
+
+ printf("VirtualBox DirectFB GUI built %s %s\n"
+ "(C) 2004-" VBOX_C_YEAR " " VBOX_VENDOR "\n"
+ "(C) 2004-2005 secunet Security Networks AG\n", __DATE__, __TIME__);
+
+ for (;;)
+ {
+ c = getopt_long(argc, argv, "s:", options, NULL);
+ if (c == -1)
+ break;
+ switch (c)
+ {
+ case 'h':
+ {
+ showusage();
+ exit(0);
+ }
+ case 's':
+ {
+ // UUID as string, parse it
+ RTUUID buuid;
+ if (!RT_SUCCESS(RTUuidFromStr((PRTUUID)&buuid, optarg)))
+ {
+ printf("Error, invalid UUID format given!\n");
+ showusage();
+ exit(-1);
+ }
+ uuid = optarg;
+ break;
+ }
+ case 'f':
+ {
+ if (sscanf(optarg, "%ux%ux%u", &fixedVideoMode.width, &fixedVideoMode.height,
+ &fixedVideoMode.bpp) != 3)
+ {
+ printf("Error, invalid resolution argument!\n");
+ showusage();
+ exit(-1);
+ }
+ useFixedVideoMode = 1;
+ break;
+ }
+ case 'l':
+ {
+ listHostModes = 1;
+ break;
+ }
+ case 'c':
+ {
+ scaleGuest = 1;
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ // check if we got a UUID
+ if (!uuid)
+ {
+ printf("Error, no UUID given!\n");
+ showusage();
+ exit(-1);
+ }
+
+
+ /**
+ * XPCOM setup
+ */
+
+ nsresult rc;
+ /*
+ * Note that we scope all nsCOMPtr variables in order to have all XPCOM
+ * objects automatically released before we call NS_ShutdownXPCOM at the
+ * end. This is an XPCOM requirement.
+ */
+ {
+ nsCOMPtr<nsIServiceManager> serviceManager;
+ rc = NS_InitXPCOM2(getter_AddRefs(serviceManager), nsnull, nsnull);
+ if (NS_FAILED(rc))
+ {
+ printf("Error: XPCOM could not be initialized! rc=0x%x\n", rc);
+ exit(-1);
+ }
+
+ // register our component
+ nsCOMPtr<nsIComponentRegistrar> registrar = do_QueryInterface(serviceManager);
+ if (!registrar)
+ {
+ printf("Error: could not query nsIComponentRegistrar interface!\n");
+ exit(-1);
+ }
+ registrar->AutoRegister(nsnull);
+
+ /*
+ * Make sure the main event queue is created. This event queue is
+ * responsible for dispatching incoming XPCOM IPC messages. The main
+ * thread should run this event queue's loop during lengthy non-XPCOM
+ * operations to ensure messages from the VirtualBox server and other
+ * XPCOM IPC clients are processed. This use case doesn't perform such
+ * operations so it doesn't run the event loop.
+ */
+ nsCOMPtr<nsIEventQueue> eventQ;
+ rc = NS_GetMainEventQ(getter_AddRefs(eventQ));
+ if (NS_FAILED(rc))
+ {
+ printf("Error: could not get main event queue! rc=%08X\n", rc);
+ return -1;
+ }
+
+ /*
+ * Now XPCOM is ready and we can start to do real work.
+ * IVirtualBox is the root interface of VirtualBox and will be
+ * retrieved from the XPCOM component manager. We use the
+ * XPCOM provided smart pointer nsCOMPtr for all objects because
+ * that's very convenient and removes the need deal with reference
+ * counting and freeing.
+ */
+ nsCOMPtr<nsIComponentManager> manager;
+ rc = NS_GetComponentManager(getter_AddRefs(manager));
+ if (NS_FAILED(rc))
+ {
+ printf("Error: could not get component manager! rc=%08X\n", rc);
+ exit(-1);
+ }
+
+ nsCOMPtr<IVirtualBox> virtualBox;
+ rc = manager->CreateInstanceByContractID(NS_VIRTUALBOX_CONTRACTID,
+ nsnull,
+ NS_GET_IID(IVirtualBox),
+ getter_AddRefs(virtualBox));
+ if (NS_FAILED(rc))
+ {
+ printf("Error, could not instantiate object! rc=0x%x\n", rc);
+ exit(-1);
+ }
+
+ nsCOMPtr<ISession> session;
+ rc = manager->CreateInstance(CLSID_Session,
+ nsnull,
+ NS_GET_IID(ISession),
+ getter_AddRefs(session));
+ if (NS_FAILED(rc))
+ {
+ printf("Error: could not instantiate Session object! rc = %08X\n", rc);
+ exit(-1);
+ }
+
+ // open session for this VM
+ rc = virtualBox->OpenSession(session, NS_ConvertUTF8toUTF16(uuid).get());
+ if (NS_FAILED(rc))
+ {
+ printf("Error: given machine not found!\n");
+ exit(-1);
+ }
+ nsCOMPtr<IMachine> machine;
+ session->GetMachine(getter_AddRefs(machine));
+ if (!machine)
+ {
+ printf("Error: given machine not found!\n");
+ exit(-1);
+ }
+ nsCOMPtr<IConsole> console;
+ session->GetConsole(getter_AddRefs(console));
+ if (!console)
+ {
+ printf("Error: cannot get console!\n");
+ exit(-1);
+ }
+
+ nsCOMPtr<IDisplay> display;
+ console->GetDisplay(getter_AddRefs(display));
+ if (!display)
+ {
+ printf("Error: could not get display object!\n");
+ exit(-1);
+ }
+
+ nsCOMPtr<IKeyboard> keyboard;
+ nsCOMPtr<IMouse> mouse;
+ VBoxDirectFB *frameBuffer = NULL;
+
+ /**
+ * Init DirectFB
+ */
+ IDirectFB *dfb = NULL;
+ IDirectFBSurface *surface = NULL;
+ IDirectFBInputDevice *dfbKeyboard = NULL;
+ IDirectFBInputDevice *dfbMouse = NULL;
+ IDirectFBEventBuffer *dfbEventBuffer = NULL;
+ DFBSurfaceDescription dsc;
+ int screen_width, screen_height;
+
+ DFBCHECK(DirectFBInit(&argc, &argv));
+ DFBCHECK(DirectFBCreate(&dfb));
+ DFBCHECK(dfb->SetCooperativeLevel(dfb, DFSCL_FULLSCREEN));
+ // populate our structure of supported video modes
+ DFBCHECK(dfb->EnumVideoModes(dfb, enumVideoModesHandler, NULL));
+
+ if (listHostModes)
+ {
+ printf("*****************************************************\n");
+ printf("Number of available host video modes: %u\n", numVideoModes);
+ for (uint32_t i = 0; i < numVideoModes; i++)
+ {
+ printf("Mode %u: xres = %u, yres = %u, bpp = %u\n", i,
+ videoModes[i].width, videoModes[i].height, videoModes[i].bpp);
+ }
+ printf("Note: display modes with bpp < have been filtered out\n");
+ printf("*****************************************************\n");
+ goto Leave;
+ }
+
+ if (useFixedVideoMode)
+ {
+ int32_t bestVideoMode = getBestVideoMode(fixedVideoMode.width,
+ fixedVideoMode.height,
+ fixedVideoMode.bpp);
+ // validate the fixed mode
+ if ((bestVideoMode == -1) ||
+ ((fixedVideoMode.width != videoModes[bestVideoMode].width) ||
+ (fixedVideoMode.height != videoModes[bestVideoMode].height) ||
+ (fixedVideoMode.bpp != videoModes[bestVideoMode].bpp)))
+ {
+ printf("Error: the specified fixed video mode is not available!\n");
+ exit(-1);
+ }
+ } else
+ {
+ initialVideoMode = getBestVideoMode(640, 480, 16);
+ if (initialVideoMode == -1)
+ {
+ printf("Error: initial video mode 640x480x16 is not available!\n");
+ exit(-1);
+ }
+ }
+
+ dsc.flags = DSDESC_CAPS;
+ dsc.caps = DSCAPS_PRIMARY;
+ DFBCHECK(dfb->CreateSurface(dfb, &dsc, &surface));
+ DFBCHECK(surface->Clear(surface, 0, 0, 0, 0));
+ DFBCHECK(surface->GetSize(surface, &screen_width, &screen_height));
+ DFBCHECK(dfb->GetInputDevice(dfb, DIDID_KEYBOARD, &dfbKeyboard));
+ DFBCHECK(dfbKeyboard->CreateEventBuffer(dfbKeyboard, &dfbEventBuffer));
+ DFBCHECK(dfb->GetInputDevice(dfb, DIDID_MOUSE, &dfbMouse));
+ DFBCHECK(dfbMouse->AttachEventBuffer(dfbMouse, dfbEventBuffer));
+
+
+ if (useFixedVideoMode)
+ {
+ printf("Information: setting video mode to %ux%ux%u\n", fixedVideoMode.width,
+ fixedVideoMode.height, fixedVideoMode.bpp);
+ DFBCHECK(dfb->SetVideoMode(dfb, fixedVideoMode.width,
+ fixedVideoMode.height, fixedVideoMode.bpp));
+ } else
+ {
+ printf("Information: starting with default video mode %ux%ux%u\n",
+ videoModes[initialVideoMode].width, videoModes[initialVideoMode].height,
+ videoModes[initialVideoMode].bpp);
+ DFBCHECK(dfb->SetVideoMode(dfb, videoModes[initialVideoMode].width,
+ videoModes[initialVideoMode].height,
+ videoModes[initialVideoMode].bpp));
+ }
+
+ // register our framebuffer
+ frameBuffer = new VBoxDirectFB(dfb, surface);
+ display->SetFramebuffer(0, frameBuffer);
+
+ /**
+ * Start the VM execution thread
+ */
+ console->PowerUp(NULL);
+
+ console->GetKeyboard(getter_AddRefs(keyboard));
+ console->GetMouse(getter_AddRefs(mouse));
+
+ /**
+ * Main event loop
+ */
+ #define MAX_KEYEVENTS 10
+ PRInt32 keyEvents[MAX_KEYEVENTS];
+ int numKeyEvents;
+
+ while (!quit)
+ {
+ DFBInputEvent event;
+
+ numKeyEvents = 0;
+ DFBCHECK(dfbEventBuffer->WaitForEvent(dfbEventBuffer));
+ while (dfbEventBuffer->GetEvent(dfbEventBuffer, DFB_EVENT(&event)) == DFB_OK)
+ {
+ int mouseXDelta = 0;
+ int mouseYDelta = 0;
+ int mouseZDelta = 0;
+ switch (event.type)
+ {
+ #define QUEUEEXT() keyEvents[numKeyEvents++] = 0xe0
+ #define QUEUEKEY(scan) keyEvents[numKeyEvents++] = scan | (event.type == DIET_KEYRELEASE ? 0x80 : 0x00)
+ #define QUEUEKEYRAW(scan) keyEvents[numKeyEvents++] = scan
+ case DIET_KEYPRESS:
+ case DIET_KEYRELEASE:
+ {
+ // @@@AH development hack to get out of it!
+ if ((event.key_id == DIKI_ESCAPE) && (event.modifiers & (DIMM_CONTROL | DIMM_ALT)))
+ quit = 1;
+
+ if (numKeyEvents < MAX_KEYEVENTS)
+ {
+ //printf("%s: key_code: 0x%x\n", event.type == DIET_KEYPRESS ? "DIET_KEYPRESS" : "DIET_KEYRELEASE", event.key_code);
+ switch ((uint32_t)event.key_id)
+ {
+ case DIKI_CONTROL_R:
+ QUEUEEXT();
+ QUEUEKEY(0x1d);
+ break;
+ case DIKI_INSERT:
+ QUEUEEXT();
+ QUEUEKEY(0x52);
+ break;
+ case DIKI_DELETE:
+ QUEUEEXT();
+ QUEUEKEY(0x53);
+ break;
+ case DIKI_HOME:
+ QUEUEEXT();
+ QUEUEKEY(0x47);
+ break;
+ case DIKI_END:
+ QUEUEEXT();
+ QUEUEKEY(0x4f);
+ break;
+ case DIKI_PAGE_UP:
+ QUEUEEXT();
+ QUEUEKEY(0x49);
+ break;
+ case DIKI_PAGE_DOWN:
+ QUEUEEXT();
+ QUEUEKEY(0x51);
+ break;
+ case DIKI_LEFT:
+ QUEUEEXT();
+ QUEUEKEY(0x4b);
+ break;
+ case DIKI_RIGHT:
+ QUEUEEXT();
+ QUEUEKEY(0x4d);
+ break;
+ case DIKI_UP:
+ QUEUEEXT();
+ QUEUEKEY(0x48);
+ break;
+ case DIKI_DOWN:
+ QUEUEEXT();
+ QUEUEKEY(0x50);
+ break;
+ case DIKI_KP_DIV:
+ QUEUEEXT();
+ QUEUEKEY(0x35);
+ break;
+ case DIKI_KP_ENTER:
+ QUEUEEXT();
+ QUEUEKEY(0x1c);
+ break;
+ case DIKI_PRINT:
+ // the break code is inverted!
+ if (event.type == DIET_KEYPRESS)
+ {
+ QUEUEEXT();
+ QUEUEKEY(0x2a);
+ QUEUEEXT();
+ QUEUEKEY(0x37);
+ } else
+ {
+ QUEUEEXT();
+ QUEUEKEY(0x37);
+ QUEUEEXT();
+ QUEUEKEY(0x2a);
+ }
+ break;
+ case DIKI_PAUSE:
+ // This is a super weird key. No break code and a 6 byte
+ // combination.
+ if (event.type == DIET_KEYPRESS)
+ {
+ QUEUEKEY(0xe1);
+ QUEUEKEY(0x1d);
+ QUEUEKEY(0x45);
+ QUEUEKEY(0xe1);
+ QUEUEKEY(0x9d);
+ QUEUEKEY(0xc5);
+ }
+ break;
+ case DIKI_META_L:
+ // the left Windows logo is a bit different
+ if (event.type == DIET_KEYPRESS)
+ {
+ QUEUEEXT();
+ QUEUEKEYRAW(0x1f);
+ } else
+ {
+ QUEUEEXT();
+ QUEUEKEYRAW(0xf0);
+ QUEUEKEYRAW(0x1f);
+ }
+ break;
+ case DIKI_META_R:
+ // the right Windows logo is a bit different
+ if (event.type == DIET_KEYPRESS)
+ {
+ QUEUEEXT();
+ QUEUEKEYRAW(0x27);
+ } else
+ {
+ QUEUEEXT();
+ QUEUEKEYRAW(0xf0);
+ QUEUEKEYRAW(0x27);
+ }
+ break;
+ case DIKI_SUPER_R:
+ // the popup menu is a bit different
+ if (event.type == DIET_KEYPRESS)
+ {
+ QUEUEEXT();
+ QUEUEKEYRAW(0x2f);
+ } else
+ {
+ QUEUEEXT();
+ QUEUEKEYRAW(0xf0);
+ QUEUEKEYRAW(0x2f);
+ }
+ break;
+
+ default:
+ // check if we got a hardware scancode
+ if (event.key_code != -1)
+ {
+ // take the scancode from DirectFB as is
+ QUEUEKEY(event.key_code);
+ } else
+ {
+ // XXX need extra handling!
+ }
+ }
+ }
+ break;
+ }
+ #undef QUEUEEXT
+ #undef QUEUEKEY
+ #undef QUEUEKEYRAW
+
+ case DIET_AXISMOTION:
+ {
+ switch (event.axis)
+ {
+ case DIAI_X:
+ mouseXDelta += event.axisrel;
+ break;
+ case DIAI_Y:
+ mouseYDelta += event.axisrel;
+ break;
+ case DIAI_Z:
+ mouseZDelta += event.axisrel;
+ break;
+ default:
+ break;
+ }
+ // fall through
+ }
+ case DIET_BUTTONPRESS:
+ // fall through;
+ case DIET_BUTTONRELEASE:
+ {
+ int buttonState = 0;
+ if (event.buttons & DIBM_LEFT)
+ buttonState |= MouseButtonState::LeftButton;
+ if (event.buttons & DIBM_RIGHT)
+ buttonState |= MouseButtonState::RightButton;
+ if (event.buttons & DIBM_MIDDLE)
+ buttonState |= MouseButtonState::MiddleButton;
+ mouse->PutMouseEvent(mouseXDelta, mouseYDelta, mouseZDelta,
+ buttonState);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ // did we get any keyboard events?
+ if (numKeyEvents > 0)
+ {
+ uint32_t codesStored;
+ if (numKeyEvents > 1)
+ {
+ keyboard->PutScancodes(numKeyEvents, keyEvents,
+ &codesStored);
+ } else
+ {
+ keyboard->PutScancode(keyEvents[0]);
+ }
+ }
+ }
+ {
+ nsCOMPtr<IProgress> progress;
+ console->PowerDown(getter_AddRefs(progress));
+ progress->WaitForCompletion(-1);
+ }
+ }
+
+Leave:
+ /*
+ * Perform the standard XPCOM shutdown procedure.
+ */
+ NS_ShutdownXPCOM(nsnull);
+
+ return 0;
+}
diff --git a/src/VBox/Frontends/VBoxFB/VBoxFB.h b/src/VBox/Frontends/VBoxFB/VBoxFB.h
new file mode 100644
index 00000000..e1e89acb
--- /dev/null
+++ b/src/VBox/Frontends/VBoxFB/VBoxFB.h
@@ -0,0 +1,81 @@
+/** @file
+ *
+ * VBox frontends: Framebuffer (FB, DirectFB):
+ * Main header file
+ */
+
+/*
+ * Copyright (C) 2006-2020 Oracle Corporation
+ *
+ * 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.
+ */
+
+#ifndef VBOX_INCLUDED_SRC_VBoxFB_VBoxFB_h
+#define VBOX_INCLUDED_SRC_VBoxFB_VBoxFB_h
+#ifndef RT_WITHOUT_PRAGMA_ONCE
+# pragma once
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+
+// XPCOM headers
+#include <nsIServiceManager.h>
+#include <nsIComponentRegistrar.h>
+#include <nsXPCOMGlue.h>
+#include <nsMemory.h>
+#include <nsIProgrammingLanguage.h>
+#include <nsIFile.h>
+#include <nsILocalFile.h>
+#include <nsString.h>
+#include <nsReadableUtils.h>
+#include <VirtualBox_XPCOM.h>
+#include <ipcIService.h>
+#include <nsEventQueueUtils.h>
+#include <ipcCID.h>
+#include <ipcIDConnectService.h>
+#define IPC_DCONNECTSERVICE_CONTRACTID \
+ "@mozilla.org/ipc/dconnect-service;1"
+
+#include <VBox/types.h>
+#include <VBox/err.h>
+#include <VBox/log.h>
+#include <iprt/assert.h>
+#include <iprt/uuid.h>
+
+// DirectFB header
+#include <directfb/directfb.h>
+
+/**
+ * Executes the passed in expression and verifies the return code.
+ *
+ * On failure a debug message is printed to stderr and the application will
+ * abort with an fatal error.
+ */
+#define DFBCHECK(x...) \
+ do { \
+ DFBResult err = x; \
+ if (err != DFB_OK) \
+ { \
+ fprintf(stderr, "%s <%d>:\n\t", __FILE__, __LINE__ ); \
+ DirectFBErrorFatal(#x, err); \
+ } \
+ } while (0)
+
+#include "Helper.h"
+
+/**
+ * Globals
+ */
+extern uint32_t useFixedVideoMode;
+extern videoMode fixedVideoMode;
+extern int scaleGuest;
+
+#endif /* !VBOX_INCLUDED_SRC_VBoxFB_VBoxFB_h */