VirtualBox

source: vbox/trunk/src/VBox/Frontends/VBoxFB/VBoxFB.cpp@ 106401

Last change on this file since 106401 was 106061, checked in by vboxsync, 3 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 23.0 KB
Line 
1/* $Id: VBoxFB.cpp 106061 2024-09-16 14:03:52Z vboxsync $ */
2/** @file
3 * VBoxFB - Linux Direct Framebuffer Frontend.
4 *
5 * @note This code has not been tested in a long time, so expect bugs if it
6 * even compiles. It is not part of any regular VirtualBox build.
7 */
8
9/*
10 * Copyright (C) 2006-2024 Oracle and/or its affiliates.
11 *
12 * This file is part of VirtualBox base platform packages, as
13 * available from https://www.virtualbox.org.
14 *
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation, in version 3 of the
18 * License.
19 *
20 * This program is distributed in the hope that it will be useful, but
21 * WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 * General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, see <https://www.gnu.org/licenses>.
27 *
28 * SPDX-License-Identifier: GPL-3.0-only
29 */
30
31#include "VBoxFB.h"
32#include "Framebuffer.h"
33#include <getopt.h>
34#include <VBox/param.h>
35#include <iprt/path.h>
36#include <VBox/version.h>
37
38/**
39 * Globals
40 */
41uint32_t g_useFixedVideoMode = 0;
42int g_scaleGuest = 0;
43videoMode g_fixedVideoMode = {0};
44int32_t g_initialVideoMode = -1;
45
46void showusage()
47{
48 printf("\nThe following parameters are supported:\n"
49 "--startvm uuid start VM with UUID 'uuid'\n"
50 "--fixedres WxHxBPP always use fixed host resolution\n"
51 "--listhostmodes display list of supported host display modes and exit\n"
52 "--scale scale guest video mode to host video mode\n"
53 "--nodirectblit disable direct blitting, use intermediate framebuffer\n"
54 "--showlabel show VM name on top of the VM display\n");
55}
56
57/** entry point */
58int main(int argc, char *argv[])
59{
60 const char *uuid = NULL;
61 int c;
62 int listHostModes = 0;
63 int quit = 0;
64 const struct option options[] =
65 {
66 { "help", no_argument, NULL, 'h' },
67 { "startvm", required_argument, NULL, 's' },
68 { "fixedres", required_argument, NULL, 'f' },
69 { "listhostmodes", no_argument, NULL, 'l' },
70 { "scale", no_argument, NULL, 'c' }
71 };
72
73 printf("VirtualBox DirectFB GUI built %s %s\n"
74 "Copyright (C) 2004-" VBOX_C_YEAR " " VBOX_VENDOR "\n"
75 "Copyright (C) 2004-2005 secunet Security Networks AG\n", __DATE__, __TIME__);
76
77 fputs("\nWARNING! Unmaintained code.\nWARNING! Needs fixing & debugging!\n\n", stdout);
78
79 for (;;)
80 {
81 c = getopt_long(argc, argv, "s:", options, NULL);
82 if (c == -1)
83 break;
84 switch (c)
85 {
86 case 'h':
87 {
88 showusage();
89 exit(0);
90 }
91 case 's':
92 {
93#if 0
94 // UUID as string, parse it
95 RTUUID buuid;
96 if (!RT_SUCCESS(RTUuidFromStr((PRTUUID)&buuid, optarg)))
97 {
98 printf("Error, invalid UUID format given!\n");
99 showusage();
100 exit(-1);
101 }
102#endif
103 uuid = optarg;
104 break;
105 }
106 case 'f':
107 {
108 if (sscanf(optarg, "%ux%ux%u", &g_fixedVideoMode.width, &g_fixedVideoMode.height,
109 &g_fixedVideoMode.bpp) != 3)
110 {
111 printf("Error, invalid resolution argument!\n");
112 showusage();
113 exit(-1);
114 }
115 g_useFixedVideoMode = 1;
116 break;
117 }
118 case 'l':
119 {
120 listHostModes = 1;
121 break;
122 }
123 case 'c':
124 {
125 g_scaleGuest = 1;
126 break;
127 }
128 default:
129 break;
130 }
131 }
132
133 // check if we got a UUID
134 if (!uuid)
135 {
136 printf("Error, no UUID given!\n");
137 showusage();
138 exit(-1);
139 }
140
141
142 /*
143 * XPCOM setup
144 */
145
146 nsresult rc;
147 /*
148 * Note that we scope all nsCOMPtr variables in order to have all XPCOM
149 * objects automatically released before we call NS_ShutdownXPCOM at the
150 * end. This is an XPCOM requirement.
151 */
152 {
153#if 0
154 nsCOMPtr<nsIServiceManager> serviceManager;
155 rc = NS_InitXPCOM2(getter_AddRefs(serviceManager), nsnull, nsnull);
156 if (NS_FAILED(rc))
157 {
158 printf("Error: XPCOM could not be initialized! rc=0x%x\n", rc);
159 exit(-1);
160 }
161
162 // register our component
163 nsCOMPtr<nsIComponentRegistrar> registrar = do_QueryInterface(serviceManager);
164 if (!registrar)
165 {
166 printf("Error: could not query nsIComponentRegistrar interface!\n");
167 exit(-1);
168 }
169 registrar->AutoRegister(nsnull);
170
171 /*
172 * Make sure the main event queue is created. This event queue is
173 * responsible for dispatching incoming XPCOM IPC messages. The main
174 * thread should run this event queue's loop during lengthy non-XPCOM
175 * operations to ensure messages from the VirtualBox server and other
176 * XPCOM IPC clients are processed. This use case doesn't perform such
177 * operations so it doesn't run the event loop.
178 */
179 nsCOMPtr<nsIEventQueue> eventQ;
180 rc = NS_GetMainEventQ(getter_AddRefs(eventQ));
181 if (NS_FAILED(rc))
182 {
183 printf("Error: could not get main event queue! rc=%08X\n", rc);
184 return -1;
185 }
186#else
187 rc = com::Initialize();
188 if (NS_FAILED(rc))
189 {
190 printf("Error: XPCOM could not be initialized! rc=0x%x\n", rc);
191 exit(-1);
192 }
193#endif
194
195 /*
196 * Now XPCOM is ready and we can start to do real work.
197 * IVirtualBox is the root interface of VirtualBox and will be
198 * retrieved from the XPCOM component manager. We use the
199 * XPCOM provided smart pointer nsCOMPtr for all objects because
200 * that's very convenient and removes the need deal with reference
201 * counting and freeing.
202 */
203 nsCOMPtr<nsIComponentManager> manager;
204 rc = NS_GetComponentManager(getter_AddRefs(manager));
205 if (NS_FAILED(rc))
206 {
207 printf("Error: could not get component manager! rc=%08X\n", rc);
208 exit(-1);
209 }
210
211 nsCOMPtr<IVirtualBox> virtualBox;
212 rc = manager->CreateInstanceByContractID(NS_VIRTUALBOX_CONTRACTID,
213 nsnull,
214 NS_GET_IID(IVirtualBox),
215 getter_AddRefs(virtualBox));
216 if (NS_FAILED(rc))
217 {
218 printf("Error, could not instantiate object! rc=0x%x\n", rc);
219 exit(-1);
220 }
221
222 nsCOMPtr<ISession> session;
223 rc = manager->CreateInstance(CLSID_Session,
224 nsnull,
225 NS_GET_IID(ISession),
226 getter_AddRefs(session));
227 if (NS_FAILED(rc))
228 {
229 printf("Error: could not instantiate Session object! rc = %08X\n", rc);
230 exit(-1);
231 }
232
233 // find the VM
234 nsCOMPtr<IMachine> machine;
235 rc = virtualBox->FindMachine(NS_ConvertUTF8toUTF16(uuid).get(), getter_AddRefs(machine));
236 if (rc != S_OK || !machine)
237 {
238 printf("Error: given machine not found!\n");
239 return RTEXITCODE_FAILURE;
240 }
241
242 // open session for this VM
243 rc = machine->LockMachine(session, LockType_VM);
244 if (NS_FAILED(rc))
245 {
246 printf("Error: given machine not found!\n");
247 exit(-1);
248 }
249 session->GetMachine(getter_AddRefs(machine));
250 if (!machine)
251 {
252 printf("Error: given machine not found!\n");
253 exit(-1);
254 }
255 nsCOMPtr<IConsole> console;
256 session->GetConsole(getter_AddRefs(console));
257 if (!console)
258 {
259 printf("Error: cannot get console!\n");
260 exit(-1);
261 }
262
263 nsCOMPtr<IDisplay> display;
264 console->GetDisplay(getter_AddRefs(display));
265 if (!display)
266 {
267 printf("Error: could not get display object!\n");
268 exit(-1);
269 }
270
271 nsCOMPtr<IKeyboard> keyboard;
272 nsCOMPtr<IMouse> mouse;
273 VBoxDirectFB *frameBuffer = NULL;
274
275 /*
276 * Init DirectFB
277 */
278 IDirectFB *dfb = NULL;
279 IDirectFBSurface *surface = NULL;
280 IDirectFBInputDevice *dfbKeyboard = NULL;
281 IDirectFBInputDevice *dfbMouse = NULL;
282 IDirectFBEventBuffer *dfbEventBuffer = NULL;
283 DFBSurfaceDescription dsc;
284 int screen_width, screen_height;
285
286 DFBCHECK(DirectFBInit(&argc, &argv));
287 DFBCHECK(DirectFBCreate(&dfb));
288 DFBCHECK(dfb->SetCooperativeLevel(dfb, DFSCL_FULLSCREEN));
289 // populate our structure of supported video modes
290 DFBCHECK(dfb->EnumVideoModes(dfb, enumVideoModesHandler, NULL));
291
292 if (listHostModes)
293 {
294 printf("*****************************************************\n");
295 printf("Number of available host video modes: %u\n", g_numVideoModes);
296 for (uint32_t i = 0; i < g_numVideoModes; i++)
297 {
298 printf("Mode %u: xres = %u, yres = %u, bpp = %u\n", i,
299 g_videoModes[i].width, g_videoModes[i].height, g_videoModes[i].bpp);
300 }
301 printf("Note: display modes with bpp < have been filtered out\n");
302 printf("*****************************************************\n");
303 goto Leave;
304 }
305
306 if (g_useFixedVideoMode)
307 {
308 int32_t bestVideoMode = getBestVideoMode(g_fixedVideoMode.width,
309 g_fixedVideoMode.height,
310 g_fixedVideoMode.bpp);
311 // validate the fixed mode
312 if ( bestVideoMode == -1
313 || g_fixedVideoMode.width != g_videoModes[bestVideoMode].width
314 || g_fixedVideoMode.height != g_videoModes[bestVideoMode].height
315 || g_fixedVideoMode.bpp != g_videoModes[bestVideoMode].bpp)
316 {
317 printf("Error: the specified fixed video mode is not available!\n");
318 exit(-1);
319 }
320 } else
321 {
322 g_initialVideoMode = getBestVideoMode(640, 480, 16);
323 if (g_initialVideoMode == -1)
324 {
325 printf("Error: initial video mode 640x480x16 is not available!\n");
326 exit(-1);
327 }
328 }
329
330 dsc.flags = DSDESC_CAPS;
331 dsc.caps = DSCAPS_PRIMARY;
332 DFBCHECK(dfb->CreateSurface(dfb, &dsc, &surface));
333 DFBCHECK(surface->Clear(surface, 0, 0, 0, 0));
334 DFBCHECK(surface->GetSize(surface, &screen_width, &screen_height));
335 DFBCHECK(dfb->GetInputDevice(dfb, DIDID_KEYBOARD, &dfbKeyboard));
336 DFBCHECK(dfbKeyboard->CreateEventBuffer(dfbKeyboard, &dfbEventBuffer));
337 DFBCHECK(dfb->GetInputDevice(dfb, DIDID_MOUSE, &dfbMouse));
338 DFBCHECK(dfbMouse->AttachEventBuffer(dfbMouse, dfbEventBuffer));
339
340
341 if (g_useFixedVideoMode)
342 {
343 printf("Information: setting video mode to %ux%ux%u\n", g_fixedVideoMode.width,
344 g_fixedVideoMode.height, g_fixedVideoMode.bpp);
345 DFBCHECK(dfb->SetVideoMode(dfb, g_fixedVideoMode.width,
346 g_fixedVideoMode.height, g_fixedVideoMode.bpp));
347 } else
348 {
349 printf("Information: starting with default video mode %ux%ux%u\n",
350 g_videoModes[g_initialVideoMode].width, g_videoModes[g_initialVideoMode].height,
351 g_videoModes[g_initialVideoMode].bpp);
352 DFBCHECK(dfb->SetVideoMode(dfb,
353 g_videoModes[g_initialVideoMode].width,
354 g_videoModes[g_initialVideoMode].height,
355 g_videoModes[g_initialVideoMode].bpp));
356 }
357
358 // register our framebuffer
359 frameBuffer = new VBoxDirectFB(dfb, surface);
360 PRUnichar *pwszFrameBufferUuid = NULL;
361 display->AttachFramebuffer(0, frameBuffer, &pwszFrameBufferUuid);
362
363 /*
364 * Start the VM execution thread
365 */
366 console->PowerUp(NULL);
367
368 console->GetKeyboard(getter_AddRefs(keyboard));
369 console->GetMouse(getter_AddRefs(mouse));
370
371 /*
372 * Main event loop
373 */
374 #define MAX_KEYEVENTS 10
375 PRInt32 keyEvents[MAX_KEYEVENTS];
376 int numKeyEvents;
377
378 while (!quit)
379 {
380 DFBInputEvent event;
381
382 numKeyEvents = 0;
383 DFBCHECK(dfbEventBuffer->WaitForEvent(dfbEventBuffer));
384 while (dfbEventBuffer->GetEvent(dfbEventBuffer, DFB_EVENT(&event)) == DFB_OK)
385 {
386 int mouseXDelta = 0;
387 int mouseYDelta = 0;
388 int mouseZDelta = 0;
389 switch (event.type)
390 {
391 #define QUEUEEXT() keyEvents[numKeyEvents++] = 0xe0
392 #define QUEUEKEY(scan) keyEvents[numKeyEvents++] = scan | (event.type == DIET_KEYRELEASE ? 0x80 : 0x00)
393 #define QUEUEKEYRAW(scan) keyEvents[numKeyEvents++] = scan
394 case DIET_KEYPRESS:
395 case DIET_KEYRELEASE:
396 {
397 // @@@AH development hack to get out of it!
398 if ((event.key_id == DIKI_ESCAPE) && (event.modifiers & (DIMM_CONTROL | DIMM_ALT)))
399 quit = 1;
400
401 if (numKeyEvents < MAX_KEYEVENTS)
402 {
403 //printf("%s: key_code: 0x%x\n", event.type == DIET_KEYPRESS ? "DIET_KEYPRESS" : "DIET_KEYRELEASE", event.key_code);
404 switch ((uint32_t)event.key_id)
405 {
406 case DIKI_CONTROL_R:
407 QUEUEEXT();
408 QUEUEKEY(0x1d);
409 break;
410 case DIKI_INSERT:
411 QUEUEEXT();
412 QUEUEKEY(0x52);
413 break;
414 case DIKI_DELETE:
415 QUEUEEXT();
416 QUEUEKEY(0x53);
417 break;
418 case DIKI_HOME:
419 QUEUEEXT();
420 QUEUEKEY(0x47);
421 break;
422 case DIKI_END:
423 QUEUEEXT();
424 QUEUEKEY(0x4f);
425 break;
426 case DIKI_PAGE_UP:
427 QUEUEEXT();
428 QUEUEKEY(0x49);
429 break;
430 case DIKI_PAGE_DOWN:
431 QUEUEEXT();
432 QUEUEKEY(0x51);
433 break;
434 case DIKI_LEFT:
435 QUEUEEXT();
436 QUEUEKEY(0x4b);
437 break;
438 case DIKI_RIGHT:
439 QUEUEEXT();
440 QUEUEKEY(0x4d);
441 break;
442 case DIKI_UP:
443 QUEUEEXT();
444 QUEUEKEY(0x48);
445 break;
446 case DIKI_DOWN:
447 QUEUEEXT();
448 QUEUEKEY(0x50);
449 break;
450 case DIKI_KP_DIV:
451 QUEUEEXT();
452 QUEUEKEY(0x35);
453 break;
454 case DIKI_KP_ENTER:
455 QUEUEEXT();
456 QUEUEKEY(0x1c);
457 break;
458 case DIKI_PRINT:
459 // the break code is inverted!
460 if (event.type == DIET_KEYPRESS)
461 {
462 QUEUEEXT();
463 QUEUEKEY(0x2a);
464 QUEUEEXT();
465 QUEUEKEY(0x37);
466 } else
467 {
468 QUEUEEXT();
469 QUEUEKEY(0x37);
470 QUEUEEXT();
471 QUEUEKEY(0x2a);
472 }
473 break;
474 case DIKI_PAUSE:
475 // This is a super weird key. No break code and a 6 byte
476 // combination.
477 if (event.type == DIET_KEYPRESS)
478 {
479 QUEUEKEY(0xe1);
480 QUEUEKEY(0x1d);
481 QUEUEKEY(0x45);
482 QUEUEKEY(0xe1);
483 QUEUEKEY(0x9d);
484 QUEUEKEY(0xc5);
485 }
486 break;
487 case DIKI_META_L:
488 // the left Windows logo is a bit different
489 if (event.type == DIET_KEYPRESS)
490 {
491 QUEUEEXT();
492 QUEUEKEYRAW(0x1f);
493 } else
494 {
495 QUEUEEXT();
496 QUEUEKEYRAW(0xf0);
497 QUEUEKEYRAW(0x1f);
498 }
499 break;
500 case DIKI_META_R:
501 // the right Windows logo is a bit different
502 if (event.type == DIET_KEYPRESS)
503 {
504 QUEUEEXT();
505 QUEUEKEYRAW(0x27);
506 } else
507 {
508 QUEUEEXT();
509 QUEUEKEYRAW(0xf0);
510 QUEUEKEYRAW(0x27);
511 }
512 break;
513 case DIKI_SUPER_R:
514 // the popup menu is a bit different
515 if (event.type == DIET_KEYPRESS)
516 {
517 QUEUEEXT();
518 QUEUEKEYRAW(0x2f);
519 } else
520 {
521 QUEUEEXT();
522 QUEUEKEYRAW(0xf0);
523 QUEUEKEYRAW(0x2f);
524 }
525 break;
526
527 default:
528 // check if we got a hardware scancode
529 if (event.key_code != -1)
530 {
531 // take the scancode from DirectFB as is
532 QUEUEKEY(event.key_code);
533 } else
534 {
535 // XXX need extra handling!
536 }
537 }
538 }
539 break;
540 }
541 #undef QUEUEEXT
542 #undef QUEUEKEY
543 #undef QUEUEKEYRAW
544
545 case DIET_AXISMOTION:
546 {
547 switch (event.axis)
548 {
549 case DIAI_X:
550 mouseXDelta += event.axisrel;
551 break;
552 case DIAI_Y:
553 mouseYDelta += event.axisrel;
554 break;
555 case DIAI_Z:
556 mouseZDelta += event.axisrel;
557 break;
558 default:
559 break;
560 }
561 // fall through
562 }
563 case DIET_BUTTONPRESS:
564 // fall through;
565 case DIET_BUTTONRELEASE:
566 {
567 int buttonState = 0;
568 if (event.buttons & DIBM_LEFT)
569 buttonState |= MouseButtonState::LeftButton;
570 if (event.buttons & DIBM_RIGHT)
571 buttonState |= MouseButtonState::RightButton;
572 if (event.buttons & DIBM_MIDDLE)
573 buttonState |= MouseButtonState::MiddleButton;
574 mouse->PutMouseEvent(mouseXDelta, mouseYDelta, mouseZDelta, 0, buttonState);
575 break;
576 }
577 default:
578 break;
579 }
580 }
581 // did we get any keyboard events?
582 if (numKeyEvents > 0)
583 {
584 uint32_t codesStored;
585 if (numKeyEvents > 1)
586 {
587 keyboard->PutScancodes(numKeyEvents, keyEvents,
588 &codesStored);
589 } else
590 {
591 keyboard->PutScancode(keyEvents[0]);
592 }
593 }
594 }
595 {
596 nsCOMPtr<IProgress> progress;
597 console->PowerDown(getter_AddRefs(progress));
598 progress->WaitForCompletion(-1);
599 }
600 }
601
602Leave:
603 /*
604 * Perform the standard XPCOM shutdown procedure.
605 */
606 NS_ShutdownXPCOM(nsnull);
607
608 return 0;
609}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette