summaryrefslogtreecommitdiffstats
path: root/src/VBox/Frontends/VBoxFB/VBoxFB.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Frontends/VBoxFB/VBoxFB.cpp')
-rw-r--r--src/VBox/Frontends/VBoxFB/VBoxFB.cpp587
1 files changed, 587 insertions, 0 deletions
diff --git a/src/VBox/Frontends/VBoxFB/VBoxFB.cpp b/src/VBox/Frontends/VBoxFB/VBoxFB.cpp
new file mode 100644
index 00000000..097caa91
--- /dev/null
+++ b/src/VBox/Frontends/VBoxFB/VBoxFB.cpp
@@ -0,0 +1,587 @@
+/** @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-2022 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+#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"
+ "Copyright (C) 2004-" VBOX_C_YEAR " " VBOX_VENDOR "\n"
+ "Copyright (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;
+}