VirtualBox

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

Last change on this file since 67954 was 62493, checked in by vboxsync, 8 years ago

(C) 2016

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