VirtualBox

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

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