VirtualBox

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

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