VirtualBox

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

Last change on this file was 109067, checked in by vboxsync, 11 days ago

libs/xpcom,Main/glue,++: Bake the automatic re-registration of XPCOM components (in the components directory) into the NS_InitXPCOM2 call to avoid the problem of VBoxXPCOMIPCC.so/dylib being engaged at the end of NS_InitXPCOM2 and unable to re-register if this is done later by the client code. Added a fFlagsInit parameter to indicate whether this auto reg behaviour is required or not and renamed NS_InitXPCOM2 to NS_InitXPCOM2Ex (the latter to prevent confusion). bugref:10896 ticketref:22193

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 22.8 KB
Line 
1/* $Id: VBoxFB.cpp 109067 2025-04-24 10:08:54Z 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_InitXPCOM2Ex(getter_AddRefs(serviceManager), nsnull, nsnull, NS_INIT_XPCOM_F_AUTO_REGISTER_COMPONENTS_WITH_STATUS);
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 /*
163 * Make sure the main event queue is created. This event queue is
164 * responsible for dispatching incoming XPCOM IPC messages. The main
165 * thread should run this event queue's loop during lengthy non-XPCOM
166 * operations to ensure messages from the VirtualBox server and other
167 * XPCOM IPC clients are processed. This use case doesn't perform such
168 * operations so it doesn't run the event loop.
169 */
170 nsCOMPtr<nsIEventQueue> eventQ;
171 rc = NS_GetMainEventQ(getter_AddRefs(eventQ));
172 if (NS_FAILED(rc))
173 {
174 printf("Error: could not get main event queue! rc=%08X\n", rc);
175 return -1;
176 }
177#else
178 rc = com::Initialize();
179 if (NS_FAILED(rc))
180 {
181 printf("Error: XPCOM could not be initialized! rc=0x%x\n", rc);
182 exit(-1);
183 }
184#endif
185
186 /*
187 * Now XPCOM is ready and we can start to do real work.
188 * IVirtualBox is the root interface of VirtualBox and will be
189 * retrieved from the XPCOM component manager. We use the
190 * XPCOM provided smart pointer nsCOMPtr for all objects because
191 * that's very convenient and removes the need deal with reference
192 * counting and freeing.
193 */
194 nsCOMPtr<nsIComponentManager> manager;
195 rc = NS_GetComponentManager(getter_AddRefs(manager));
196 if (NS_FAILED(rc))
197 {
198 printf("Error: could not get component manager! rc=%08X\n", rc);
199 exit(-1);
200 }
201
202 nsCOMPtr<IVirtualBox> virtualBox;
203 rc = manager->CreateInstanceByContractID(NS_VIRTUALBOX_CONTRACTID,
204 nsnull,
205 NS_GET_IID(IVirtualBox),
206 getter_AddRefs(virtualBox));
207 if (NS_FAILED(rc))
208 {
209 printf("Error, could not instantiate object! rc=0x%x\n", rc);
210 exit(-1);
211 }
212
213 nsCOMPtr<ISession> session;
214 rc = manager->CreateInstance(CLSID_Session,
215 nsnull,
216 NS_GET_IID(ISession),
217 getter_AddRefs(session));
218 if (NS_FAILED(rc))
219 {
220 printf("Error: could not instantiate Session object! rc = %08X\n", rc);
221 exit(-1);
222 }
223
224 // find the VM
225 nsCOMPtr<IMachine> machine;
226 rc = virtualBox->FindMachine(NS_ConvertUTF8toUTF16(uuid).get(), getter_AddRefs(machine));
227 if (rc != S_OK || !machine)
228 {
229 printf("Error: given machine not found!\n");
230 return RTEXITCODE_FAILURE;
231 }
232
233 // open session for this VM
234 rc = machine->LockMachine(session, LockType_VM);
235 if (NS_FAILED(rc))
236 {
237 printf("Error: given machine not found!\n");
238 exit(-1);
239 }
240 session->GetMachine(getter_AddRefs(machine));
241 if (!machine)
242 {
243 printf("Error: given machine not found!\n");
244 exit(-1);
245 }
246 nsCOMPtr<IConsole> console;
247 session->GetConsole(getter_AddRefs(console));
248 if (!console)
249 {
250 printf("Error: cannot get console!\n");
251 exit(-1);
252 }
253
254 nsCOMPtr<IDisplay> display;
255 console->GetDisplay(getter_AddRefs(display));
256 if (!display)
257 {
258 printf("Error: could not get display object!\n");
259 exit(-1);
260 }
261
262 nsCOMPtr<IKeyboard> keyboard;
263 nsCOMPtr<IMouse> mouse;
264 VBoxDirectFB *frameBuffer = NULL;
265
266 /*
267 * Init DirectFB
268 */
269 IDirectFB *dfb = NULL;
270 IDirectFBSurface *surface = NULL;
271 IDirectFBInputDevice *dfbKeyboard = NULL;
272 IDirectFBInputDevice *dfbMouse = NULL;
273 IDirectFBEventBuffer *dfbEventBuffer = NULL;
274 DFBSurfaceDescription dsc;
275 int screen_width, screen_height;
276
277 DFBCHECK(DirectFBInit(&argc, &argv));
278 DFBCHECK(DirectFBCreate(&dfb));
279 DFBCHECK(dfb->SetCooperativeLevel(dfb, DFSCL_FULLSCREEN));
280 // populate our structure of supported video modes
281 DFBCHECK(dfb->EnumVideoModes(dfb, enumVideoModesHandler, NULL));
282
283 if (listHostModes)
284 {
285 printf("*****************************************************\n");
286 printf("Number of available host video modes: %u\n", g_numVideoModes);
287 for (uint32_t i = 0; i < g_numVideoModes; i++)
288 {
289 printf("Mode %u: xres = %u, yres = %u, bpp = %u\n", i,
290 g_videoModes[i].width, g_videoModes[i].height, g_videoModes[i].bpp);
291 }
292 printf("Note: display modes with bpp < have been filtered out\n");
293 printf("*****************************************************\n");
294 goto Leave;
295 }
296
297 if (g_useFixedVideoMode)
298 {
299 int32_t bestVideoMode = getBestVideoMode(g_fixedVideoMode.width,
300 g_fixedVideoMode.height,
301 g_fixedVideoMode.bpp);
302 // validate the fixed mode
303 if ( bestVideoMode == -1
304 || g_fixedVideoMode.width != g_videoModes[bestVideoMode].width
305 || g_fixedVideoMode.height != g_videoModes[bestVideoMode].height
306 || g_fixedVideoMode.bpp != g_videoModes[bestVideoMode].bpp)
307 {
308 printf("Error: the specified fixed video mode is not available!\n");
309 exit(-1);
310 }
311 } else
312 {
313 g_initialVideoMode = getBestVideoMode(640, 480, 16);
314 if (g_initialVideoMode == -1)
315 {
316 printf("Error: initial video mode 640x480x16 is not available!\n");
317 exit(-1);
318 }
319 }
320
321 dsc.flags = DSDESC_CAPS;
322 dsc.caps = DSCAPS_PRIMARY;
323 DFBCHECK(dfb->CreateSurface(dfb, &dsc, &surface));
324 DFBCHECK(surface->Clear(surface, 0, 0, 0, 0));
325 DFBCHECK(surface->GetSize(surface, &screen_width, &screen_height));
326 DFBCHECK(dfb->GetInputDevice(dfb, DIDID_KEYBOARD, &dfbKeyboard));
327 DFBCHECK(dfbKeyboard->CreateEventBuffer(dfbKeyboard, &dfbEventBuffer));
328 DFBCHECK(dfb->GetInputDevice(dfb, DIDID_MOUSE, &dfbMouse));
329 DFBCHECK(dfbMouse->AttachEventBuffer(dfbMouse, dfbEventBuffer));
330
331
332 if (g_useFixedVideoMode)
333 {
334 printf("Information: setting video mode to %ux%ux%u\n", g_fixedVideoMode.width,
335 g_fixedVideoMode.height, g_fixedVideoMode.bpp);
336 DFBCHECK(dfb->SetVideoMode(dfb, g_fixedVideoMode.width,
337 g_fixedVideoMode.height, g_fixedVideoMode.bpp));
338 } else
339 {
340 printf("Information: starting with default video mode %ux%ux%u\n",
341 g_videoModes[g_initialVideoMode].width, g_videoModes[g_initialVideoMode].height,
342 g_videoModes[g_initialVideoMode].bpp);
343 DFBCHECK(dfb->SetVideoMode(dfb,
344 g_videoModes[g_initialVideoMode].width,
345 g_videoModes[g_initialVideoMode].height,
346 g_videoModes[g_initialVideoMode].bpp));
347 }
348
349 // register our framebuffer
350 frameBuffer = new VBoxDirectFB(dfb, surface);
351 PRUnichar *pwszFrameBufferUuid = NULL;
352 display->AttachFramebuffer(0, frameBuffer, &pwszFrameBufferUuid);
353
354 /*
355 * Start the VM execution thread
356 */
357 console->PowerUp(NULL);
358
359 console->GetKeyboard(getter_AddRefs(keyboard));
360 console->GetMouse(getter_AddRefs(mouse));
361
362 /*
363 * Main event loop
364 */
365 #define MAX_KEYEVENTS 10
366 PRInt32 keyEvents[MAX_KEYEVENTS];
367 int numKeyEvents;
368
369 while (!quit)
370 {
371 DFBInputEvent event;
372
373 numKeyEvents = 0;
374 DFBCHECK(dfbEventBuffer->WaitForEvent(dfbEventBuffer));
375 while (dfbEventBuffer->GetEvent(dfbEventBuffer, DFB_EVENT(&event)) == DFB_OK)
376 {
377 int mouseXDelta = 0;
378 int mouseYDelta = 0;
379 int mouseZDelta = 0;
380 switch (event.type)
381 {
382 #define QUEUEEXT() keyEvents[numKeyEvents++] = 0xe0
383 #define QUEUEKEY(scan) keyEvents[numKeyEvents++] = scan | (event.type == DIET_KEYRELEASE ? 0x80 : 0x00)
384 #define QUEUEKEYRAW(scan) keyEvents[numKeyEvents++] = scan
385 case DIET_KEYPRESS:
386 case DIET_KEYRELEASE:
387 {
388 // @@@AH development hack to get out of it!
389 if ((event.key_id == DIKI_ESCAPE) && (event.modifiers & (DIMM_CONTROL | DIMM_ALT)))
390 quit = 1;
391
392 if (numKeyEvents < MAX_KEYEVENTS)
393 {
394 //printf("%s: key_code: 0x%x\n", event.type == DIET_KEYPRESS ? "DIET_KEYPRESS" : "DIET_KEYRELEASE", event.key_code);
395 switch ((uint32_t)event.key_id)
396 {
397 case DIKI_CONTROL_R:
398 QUEUEEXT();
399 QUEUEKEY(0x1d);
400 break;
401 case DIKI_INSERT:
402 QUEUEEXT();
403 QUEUEKEY(0x52);
404 break;
405 case DIKI_DELETE:
406 QUEUEEXT();
407 QUEUEKEY(0x53);
408 break;
409 case DIKI_HOME:
410 QUEUEEXT();
411 QUEUEKEY(0x47);
412 break;
413 case DIKI_END:
414 QUEUEEXT();
415 QUEUEKEY(0x4f);
416 break;
417 case DIKI_PAGE_UP:
418 QUEUEEXT();
419 QUEUEKEY(0x49);
420 break;
421 case DIKI_PAGE_DOWN:
422 QUEUEEXT();
423 QUEUEKEY(0x51);
424 break;
425 case DIKI_LEFT:
426 QUEUEEXT();
427 QUEUEKEY(0x4b);
428 break;
429 case DIKI_RIGHT:
430 QUEUEEXT();
431 QUEUEKEY(0x4d);
432 break;
433 case DIKI_UP:
434 QUEUEEXT();
435 QUEUEKEY(0x48);
436 break;
437 case DIKI_DOWN:
438 QUEUEEXT();
439 QUEUEKEY(0x50);
440 break;
441 case DIKI_KP_DIV:
442 QUEUEEXT();
443 QUEUEKEY(0x35);
444 break;
445 case DIKI_KP_ENTER:
446 QUEUEEXT();
447 QUEUEKEY(0x1c);
448 break;
449 case DIKI_PRINT:
450 // the break code is inverted!
451 if (event.type == DIET_KEYPRESS)
452 {
453 QUEUEEXT();
454 QUEUEKEY(0x2a);
455 QUEUEEXT();
456 QUEUEKEY(0x37);
457 } else
458 {
459 QUEUEEXT();
460 QUEUEKEY(0x37);
461 QUEUEEXT();
462 QUEUEKEY(0x2a);
463 }
464 break;
465 case DIKI_PAUSE:
466 // This is a super weird key. No break code and a 6 byte
467 // combination.
468 if (event.type == DIET_KEYPRESS)
469 {
470 QUEUEKEY(0xe1);
471 QUEUEKEY(0x1d);
472 QUEUEKEY(0x45);
473 QUEUEKEY(0xe1);
474 QUEUEKEY(0x9d);
475 QUEUEKEY(0xc5);
476 }
477 break;
478 case DIKI_META_L:
479 // the left Windows logo is a bit different
480 if (event.type == DIET_KEYPRESS)
481 {
482 QUEUEEXT();
483 QUEUEKEYRAW(0x1f);
484 } else
485 {
486 QUEUEEXT();
487 QUEUEKEYRAW(0xf0);
488 QUEUEKEYRAW(0x1f);
489 }
490 break;
491 case DIKI_META_R:
492 // the right Windows logo is a bit different
493 if (event.type == DIET_KEYPRESS)
494 {
495 QUEUEEXT();
496 QUEUEKEYRAW(0x27);
497 } else
498 {
499 QUEUEEXT();
500 QUEUEKEYRAW(0xf0);
501 QUEUEKEYRAW(0x27);
502 }
503 break;
504 case DIKI_SUPER_R:
505 // the popup menu is a bit different
506 if (event.type == DIET_KEYPRESS)
507 {
508 QUEUEEXT();
509 QUEUEKEYRAW(0x2f);
510 } else
511 {
512 QUEUEEXT();
513 QUEUEKEYRAW(0xf0);
514 QUEUEKEYRAW(0x2f);
515 }
516 break;
517
518 default:
519 // check if we got a hardware scancode
520 if (event.key_code != -1)
521 {
522 // take the scancode from DirectFB as is
523 QUEUEKEY(event.key_code);
524 } else
525 {
526 // XXX need extra handling!
527 }
528 }
529 }
530 break;
531 }
532 #undef QUEUEEXT
533 #undef QUEUEKEY
534 #undef QUEUEKEYRAW
535
536 case DIET_AXISMOTION:
537 {
538 switch (event.axis)
539 {
540 case DIAI_X:
541 mouseXDelta += event.axisrel;
542 break;
543 case DIAI_Y:
544 mouseYDelta += event.axisrel;
545 break;
546 case DIAI_Z:
547 mouseZDelta += event.axisrel;
548 break;
549 default:
550 break;
551 }
552 // fall through
553 }
554 case DIET_BUTTONPRESS:
555 // fall through;
556 case DIET_BUTTONRELEASE:
557 {
558 int buttonState = 0;
559 if (event.buttons & DIBM_LEFT)
560 buttonState |= MouseButtonState::LeftButton;
561 if (event.buttons & DIBM_RIGHT)
562 buttonState |= MouseButtonState::RightButton;
563 if (event.buttons & DIBM_MIDDLE)
564 buttonState |= MouseButtonState::MiddleButton;
565 mouse->PutMouseEvent(mouseXDelta, mouseYDelta, mouseZDelta, 0, buttonState);
566 break;
567 }
568 default:
569 break;
570 }
571 }
572 // did we get any keyboard events?
573 if (numKeyEvents > 0)
574 {
575 uint32_t codesStored;
576 if (numKeyEvents > 1)
577 {
578 keyboard->PutScancodes(numKeyEvents, keyEvents,
579 &codesStored);
580 } else
581 {
582 keyboard->PutScancode(keyEvents[0]);
583 }
584 }
585 }
586 {
587 nsCOMPtr<IProgress> progress;
588 console->PowerDown(getter_AddRefs(progress));
589 progress->WaitForCompletion(-1);
590 }
591 }
592
593Leave:
594 /*
595 * Perform the standard XPCOM shutdown procedure.
596 */
597 NS_ShutdownXPCOM(nsnull);
598
599 return 0;
600}
Note: See TracBrowser for help on using the repository browser.

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