VirtualBox

source: vbox/trunk/src/VBox/Frontends/VBoxHeadless/FramebufferVNC.cpp@ 28587

Last change on this file since 28587 was 28217, checked in by vboxsync, 15 years ago

Rephrased contribution (with permission from author).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 20.2 KB
Line 
1/* $Id: FramebufferVNC.cpp 28217 2010-04-12 15:48:45Z vboxsync $ */
2/** @file
3 * VBoxHeadless - VNC server implementation for VirtualBox.
4 *
5 * Uses LibVNCServer (http://sourceforge.net/projects/libvncserver/)
6 */
7
8/*
9 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
10 *
11 * Contributed by Ivo Smits <[email protected]>
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 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
22 * Clara, CA 95054 USA or visit http://www.sun.com if you need
23 * additional information or have any questions.
24 */
25
26#include "FramebufferVNC.h"
27
28#include <iprt/assert.h>
29#include <iprt/mem.h>
30#include <VBox/log.h>
31#include <iprt/param.h>
32#include <iprt/stream.h>
33#include <iprt/thread.h>
34
35#include <png.h>
36#include <rfb/rfb.h>
37
38// constructor / destructor
39/////////////////////////////////////////////////////////////////////////////
40
41/**
42 * Perform parts of initialisation which are guaranteed not to fail
43 * unless we run out of memory. In this case, we just set the guest
44 * buffer to 0 so that RequestResize() does not free it the first time
45 * it is called.
46 */
47VNCFB::VNCFB(ComPtr <IConsole> console, int port, const char *password) :
48 mPixelFormat(FramebufferPixelFormat_Opaque),
49 mBitsPerPixel(0),
50 mBytesPerLine(0),
51 mRGBBuffer(0),
52 mScreenBuffer(0),
53 mVncPort(port),
54 mConsole(console),
55 mKeyboard(0),
56 mMouse(0),
57 mWidth(800), mHeight(600),
58 vncServer(0),
59 mVncPassword(password)
60{
61 LogFlow(("Creating VNC object %p, width=%u, height=%u, port=%u\n",
62 this, mWidth, mHeight, mVncPort));
63}
64
65
66VNCFB::~VNCFB() {
67 LogFlow(("Destroying VNCFB object %p\n", this));
68 RTCritSectDelete(&mCritSect);
69 if (vncServer) {
70 if (vncServer->authPasswdData) {
71 char **papszPassword = (char **)vncServer->authPasswdData;
72 vncServer->authPasswdData = NULL;
73 RTMemFree(papszPassword[0]);
74 RTMemFree(papszPassword);
75 }
76 rfbScreenCleanup(vncServer);
77 }
78 RTMemFree(mRGBBuffer);
79 mRGBBuffer = NULL;
80 RTMemFree(mScreenBuffer);
81 mScreenBuffer = NULL;
82}
83
84HRESULT VNCFB::init() {
85 LogFlow(("Initialising VNCFB object %p\n", this));
86 int rc = RTCritSectInit(&mCritSect);
87 AssertReturn(rc == VINF_SUCCESS, E_UNEXPECTED);
88
89 vncServer = rfbGetScreen(0, NULL, mWidth, mHeight, 8, 3, 1);
90 vncServer->screenData = (void*)this;
91 if (mVncPort) vncServer->port = mVncPort;
92 vncServer->desktopName = "VirtualBox";
93
94 if (mVncPassword) {
95 char **papszPasswords = (char **)RTMemAlloc(2 * sizeof(char **));
96 papszPasswords[0] = RTStrDup(mVncPassword);
97 papszPasswords[1] = NULL;
98 vncServer->authPasswdData = papszPasswords;
99 vncServer->passwordCheck = rfbCheckPasswordByList; //Password list based authentication function
100 } else {
101 vncServer->authPasswdData = NULL;
102 }
103
104 rfbInitServer(vncServer);
105 vncServer->kbdAddEvent = vncKeyboardEvent;
106 vncServer->kbdReleaseAllKeys = vncReleaseKeysEvent;
107 vncServer->ptrAddEvent = vncMouseEvent;
108
109 /* Set the initial framebuffer size */
110 BOOL finished;
111 RequestResize(0, FramebufferPixelFormat_Opaque, NULL, 0, 0, mWidth, mHeight, &finished);
112
113 rc = RTThreadCreate(&mVncThread, vncThreadFn, vncServer,
114 0 /*cbStack*/, RTTHREADTYPE_GUI, 0 /*fFlags*/, "VNC");
115 AssertRCReturn(rc, E_UNEXPECTED);
116
117 return S_OK;
118}
119
120DECLCALLBACK(int) VNCFB::vncThreadFn(RTTHREAD hThreadSelf, void *pvUser)
121{
122 rfbRunEventLoop((rfbScreenInfoPtr)pvUser, -1, FALSE);
123 return VINF_SUCCESS;
124}
125
126void VNCFB::vncMouseEvent(int buttonMask, int x, int y, rfbClientPtr cl) {
127 ((VNCFB*)(cl->screen->screenData))->handleVncMouseEvent(buttonMask, x, y);
128 rfbDefaultPtrAddEvent(buttonMask, x, y, cl);
129}
130
131void VNCFB::handleVncMouseEvent(int buttonMask, int x, int y) {
132 //RTPrintf("VNC mouse: button=%d x=%d y=%d\n", buttonMask, x, y);
133 if (!mMouse) {
134 this->mConsole->COMGETTER(Mouse)(mMouse.asOutParam());
135 if (!mMouse) {
136 RTPrintf("Warning: could not get mouse object!\n");
137 return;
138 }
139 }
140 int dz = 0, buttons = 0;
141 if (buttonMask & 16) dz = 1; else if (buttonMask & 8) dz = -1;
142 if (buttonMask & 1) buttons |= 1;
143 if (buttonMask & 2) buttons |= 4;
144 if (buttonMask & 4) buttons |= 2;
145 mMouse->PutMouseEvent(x - mouseX, y - mouseY, dz, 0, buttons);
146 //mMouse->PutMouseEventAbsolute(x + 1, y + 1, dz, 0, buttonMask);
147 mouseX = x;
148 mouseY = y;
149}
150
151void VNCFB::kbdPutCode(int code) {
152 mKeyboard->PutScancode(code);
153}
154void VNCFB::kbdSetShift(int state) {
155 if (state && !kbdShiftState) {
156 kbdPutCode(0x2a, 1);
157 kbdShiftState = 1;
158 } else if (!state && kbdShiftState) {
159 kbdPutCode(0x2a, 0);
160 kbdShiftState = 0;
161 }
162}
163void VNCFB::kbdPutCode(int code, int down) {
164 if (code & 0xff00) kbdPutCode((code >> 8) & 0xff);
165 kbdPutCode((code & 0xff) | (down ? 0 : 0x80));
166}
167void VNCFB::kbdPutCodeShift(int shift, int code, int down) {
168 if (shift != kbdShiftState) kbdPutCode(0x2a, shift);
169 kbdPutCode(code, down);
170 if (shift != kbdShiftState) kbdPutCode(0x2a, kbdShiftState);
171}
172
173/* Handle VNC keyboard code (X11 compatible?) to AT scancode conversion.
174 * Have tried the code from the SDL frontend, but that didn't work.
175 * Now we're using one lookup table for the lower X11 key codes (ASCII characters)
176 * and a switch() block to handle some special keys. */
177void VNCFB::handleVncKeyboardEvent(int down, int keycode) {
178 //RTPrintf("VNC keyboard: down=%d code=%d -> ", down, keycode);
179 if (mKeyboard == NULL) {
180 this->mConsole->COMGETTER(Keyboard)(mKeyboard.asOutParam());
181 if (!mKeyboard) {
182 RTPrintf("Warning: could not get keyboard object!\n");
183 return;
184 }
185 }
186 /* Conversion table for key code range 32-127 (which happen to equal the ASCII codes)
187 * The values in the table differ slightly from the actual scancode values that will be sent,
188 * values 0xe0?? indicate that a 0xe0 scancode will be sent first (extended keys), then code ?? is sent
189 * values 0x01?? indicate that the shift key must be 'down', then ?? is sent
190 * values 0x00?? or 0x?? indicate that the shift key must be 'up', then ?? is sent
191 * values 0x02?? indicate that the shift key can be ignored, and scancode ?? is sent
192 * This is necessary because the VNC protocol sends a shift key sequence, but also
193 * sends the 'shifted' version of the characters. */
194 static int codes_low[] = { //Conversion table for VNC key code range 32-127
195 0x0239, 0x0102, 0x0128, 0x0104, 0x0105, 0x0106, 0x0108, 0x0028, 0x010a, 0x010b, 0x0109, 0x010d, 0x0029, 0x000c, 0x0034, 0x0035, //space, !"#$%&'()*+`-./
196 0x0b, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, //0123456789
197 0x0127, 0x0027, 0x0133, 0x000d, 0x0134, 0x0135, 0x0103, //:;<=>?@
198 0x11e, 0x130, 0x12e, 0x120, 0x112, 0x121, 0x122, 0x123, 0x117, 0x124, 0x125, 0x126, 0x132, 0x131, 0x118, 0x119, 0x110, 0x113, 0x11f, 0x114, 0x116, 0x12f, 0x111, 0x12d, 0x115, 0x12c, //A-Z
199 0x001a, 0x002b, 0x001b, 0x0107, 0x010c, 0x0029, //[\]^_`
200 0x1e, 0x30, 0x2e, 0x20, 0x12, 0x21, 0x22, 0x23, 0x17, 0x24, 0x25, 0x26, 0x32, 0x31, 0x18, 0x19, 0x10, 0x13, 0x1f, 0x14, 0x16, 0x2f, 0x11, 0x2d, 0x15, 0x2c, //a-z
201 0x011a, 0x012b, 0x011b, 0x0129 //{|}~
202 };
203 int shift = -1, code = -1;
204 if (keycode < 32) { //ASCII control codes.. unused..
205 } else if (keycode < 127) { //DEL is in high area
206 code = codes_low[keycode - 32];
207 shift = (code >> 8) & 0x03; if (shift == 0x02 || code & 0xe000) shift = -1;
208 code = code & 0xe0ff;
209 } else if ((keycode & 0xFF00) != 0xFF00) {
210 } else {
211 switch(keycode) {
212/*Numpad keys - these have to be implemented yet
213Todo: numpad arrows, home, pageup, pagedown, end, insert, delete
21465421 Numpad return
215
21665450 Numpad *
21765451 Numpad +
21865453 Numpad -
21965454 Numpad .
22065455 Numpad /
22165457 Numpad 1
22265458 Numpad 2
22365459 Numpad 3
224
22565460 Numpad 4
22665461 Numpad 5
22765462 Numpad 6
22865463 Numpad 7
22965464 Numpad 8
23065465 Numpad 9
23165456 Numpad 0
232*/
233 case 65288: code = 0x0e; break; //Backspace
234 case 65289: code = 0x0f; break; //Tab
235
236 case 65293: code = 0x1c; break; //Return
237 //case 65299: break; Pause/break
238 case 65307: code = 0x01; break; //Escape
239
240 case 65360: code = 0xe047; break; //Home
241 case 65361: code = 0xe04b; break; //Left
242 case 65362: code = 0xe048; break; //Up
243 case 65363: code = 0xe04d; break; //Right
244 case 65364: code = 0xe050; break; //Down
245 case 65365: code = 0xe049; break; //Page up
246 case 65366: code = 0xe051; break; //Page down
247 case 65367: code = 0xe04f; break; //End
248
249 //case 65377: break; //Print screen
250 case 65379: code = 0xe052; break; //Insert
251
252 case 65383: code = 0xe05d; break; //Menu
253
254 case 65470: code = 0x3b; break; //F1
255 case 65471: code = 0x3c; break; //F2
256 case 65472: code = 0x3d; break; //F3
257 case 65473: code = 0x3e; break; //F4
258 case 65474: code = 0x3f; break; //F5
259 case 65475: code = 0x40; break; //F6
260 case 65476: code = 0x41; break; //F7
261 case 65477: code = 0x42; break; //F8
262 case 65478: code = 0x43; break; //F9
263 case 65479: code = 0x44; break; //F10
264 case 65480: code = 0x57; break; //F11
265 case 65481: code = 0x58; break; //F12
266
267 case 65505: shift = down; break; //Shift (left + right)
268 case 65507: code = 0x1d; break; //Left ctrl
269 case 65508: code = 0xe01d; break; //Right ctrl
270 case 65513: code = 0x38; break; //Left Alt
271 case 65514: code = 0xe038; break; //Right Alt
272 case 65515: code = 0xe05b; break; //Left windows key
273 case 65516: code = 0xe05c; break; //Right windows key
274 case 65535: code = 0xe053; break; //Delete
275 default: RTPrintf("VNC unhandled keyboard code: down=%d code=%d\n", down, keycode); break;
276 }
277 }
278 //RTPrintf("down=%d shift=%d code=%d\n", down, shift, code);
279 if (shift != -1 && code != -1) {
280 kbdPutCodeShift(shift, code, down);
281 } else if (shift != -1) {
282 kbdSetShift(shift);
283 } else if (code != -1) {
284 kbdPutCode(code, down);
285 }
286}
287void VNCFB::handleVncKeyboardReleaseEvent() {
288 kbdSetShift(0);
289 kbdPutCode(0x1d, 0); //Left ctrl
290 kbdPutCode(0xe01d, 0); //Right ctrl
291 kbdPutCode(0x38, 0); //Left alt
292 kbdPutCode(0xe038, 0); //Right alt
293}
294
295void VNCFB::vncKeyboardEvent(rfbBool down, rfbKeySym keySym, rfbClientPtr cl) {
296 ((VNCFB*)(cl->screen->screenData))->handleVncKeyboardEvent(down, keySym);
297}
298void VNCFB::vncReleaseKeysEvent(rfbClientPtr cl) { //Release modifier keys
299 ((VNCFB*)(cl->screen->screenData))->handleVncKeyboardReleaseEvent();
300}
301
302// IFramebuffer properties
303/////////////////////////////////////////////////////////////////////////////
304/**
305 * Requests a resize of our "screen".
306 *
307 * @returns COM status code
308 * @param pixelFormat Layout of the guest video RAM (i.e. 16, 24,
309 * 32 bpp)
310 * @param vram host context pointer to the guest video RAM,
311 * in case we can cope with the format
312 * @param bitsPerPixel color depth of the guest video RAM
313 * @param bytesPerLine length of a screen line in the guest video RAM
314 * @param w video mode width in pixels
315 * @param h video mode height in pixels
316 * @retval finished set to true if the method is synchronous and
317 * to false otherwise
318 *
319 * This method is called when the guest attempts to resize the virtual
320 * screen. The pointer to the guest's video RAM is supplied in case
321 * the framebuffer can handle the pixel format. If it can't, it should
322 * allocate a memory buffer itself, and the virtual VGA device will copy
323 * the guest VRAM to that in a format we can handle. The
324 * COMGETTER(UsesGuestVRAM) method is used to tell the VGA device which method
325 * we have chosen, and the other COMGETTER methods tell the device about
326 * the layout of our buffer. We currently handle all VRAM layouts except
327 * FramebufferPixelFormat_Opaque (which cannot be handled by
328 * definition).
329 */
330STDMETHODIMP VNCFB::RequestResize(ULONG aScreenId, ULONG pixelFormat,
331 BYTE *vram, ULONG bitsPerPixel,
332 ULONG bytesPerLine,
333 ULONG w, ULONG h, BOOL *finished) {
334 NOREF(aScreenId);
335 if (!finished) return E_POINTER;
336
337 /* For now, we are doing things synchronously */
338 *finished = true;
339
340 if (mRGBBuffer) RTMemFree(mRGBBuffer);
341
342 mWidth = w;
343 mHeight = h;
344
345 if (pixelFormat == FramebufferPixelFormat_FOURCC_RGB && bitsPerPixel == 32) {
346 mPixelFormat = FramebufferPixelFormat_FOURCC_RGB;
347 mBufferAddress = reinterpret_cast<uint8_t *>(vram);
348 mBytesPerLine = bytesPerLine;
349 mBitsPerPixel = bitsPerPixel;
350 mRGBBuffer = NULL;
351 } else {
352 mPixelFormat = FramebufferPixelFormat_FOURCC_RGB;
353 mBytesPerLine = w * 4;
354 mBitsPerPixel = 32;
355 mRGBBuffer = reinterpret_cast<uint8_t *>(RTMemAlloc(mBytesPerLine * h));
356 AssertReturn(mRGBBuffer != 0, E_OUTOFMEMORY);
357 mBufferAddress = mRGBBuffer;
358 }
359
360 uint8_t *oldBuffer = mScreenBuffer;
361 mScreenBuffer = reinterpret_cast<uint8_t *>(RTMemAlloc(mBytesPerLine * h));
362 AssertReturn(mScreenBuffer != 0, E_OUTOFMEMORY);
363
364 for (ULONG i = 0; i < mBytesPerLine * h; i += 4) {
365 mScreenBuffer[i] = mBufferAddress[i+2];
366 mScreenBuffer[i+1] = mBufferAddress[i+1];
367 mScreenBuffer[i+2] = mBufferAddress[i];
368 }
369
370 RTPrintf("Set framebuffer: buffer=%d w=%lu h=%lu bpp=%d\n", mBufferAddress, mWidth, mHeight, (int)mBitsPerPixel);
371 rfbNewFramebuffer(vncServer, (char*)mScreenBuffer, mWidth, mHeight, 8, 3, mBitsPerPixel / 8);
372 if (oldBuffer) RTMemFree(oldBuffer);
373 return S_OK;
374}
375
376//Guest framebuffer update notification
377STDMETHODIMP VNCFB::NotifyUpdate(ULONG x, ULONG y, ULONG w, ULONG h) {
378 if (!mBufferAddress || !mScreenBuffer) return S_OK;
379 ULONG joff = y * mBytesPerLine + x * 4;
380 for (ULONG j = joff; j < joff + h * mBytesPerLine; j += mBytesPerLine)
381 for (ULONG i = j; i < j + w * 4; i += 4) {
382 mScreenBuffer[i] = mBufferAddress[i+2];
383 mScreenBuffer[i+1] = mBufferAddress[i+1];
384 mScreenBuffer[i+2] = mBufferAddress[i];
385 }
386 rfbMarkRectAsModified(vncServer, x, y, x+w, y+h);
387 return S_OK;
388}
389
390
391
392
393/**
394 * Return the address of the frame buffer for the virtual VGA device to
395 * write to. If COMGETTER(UsesGuestVRAM) returns FLASE (or if this address
396 * is not the same as the guests VRAM buffer), the device will perform
397 * translation.
398 *
399 * @returns COM status code
400 * @retval address The address of the buffer
401 */
402STDMETHODIMP VNCFB::COMGETTER(Address) (BYTE **address) {
403 if (!address) return E_POINTER;
404 LogFlow(("FFmpeg::COMGETTER(Address): returning address %p\n", mBufferAddress));
405 *address = mBufferAddress;
406 return S_OK;
407}
408
409/**
410 * Return the width of our frame buffer.
411 *
412 * @returns COM status code
413 * @retval width The width of the frame buffer
414 */
415STDMETHODIMP VNCFB::COMGETTER(Width) (ULONG *width) {
416 if (!width) return E_POINTER;
417 LogFlow(("FFmpeg::COMGETTER(Width): returning width %lu\n", (unsigned long) mWidth));
418 *width = mWidth;
419 return S_OK;
420}
421
422/**
423 * Return the height of our frame buffer.
424 *
425 * @returns COM status code
426 * @retval height The height of the frame buffer
427 */
428STDMETHODIMP VNCFB::COMGETTER(Height) (ULONG *height) {
429 if (!height) return E_POINTER;
430 LogFlow(("FFmpeg::COMGETTER(Height): returning height %lu\n", (unsigned long) mHeight));
431 *height = mHeight;
432 return S_OK;
433}
434
435/**
436 * Return the colour depth of our frame buffer. Note that we actually
437 * store the pixel format, not the colour depth internally, since
438 * when display sets FramebufferPixelFormat_Opaque, it
439 * wants to retreive FramebufferPixelFormat_Opaque and
440 * nothing else.
441 *
442 * @returns COM status code
443 * @retval bitsPerPixel The colour depth of the frame buffer
444 */
445STDMETHODIMP VNCFB::COMGETTER(BitsPerPixel) (ULONG *bitsPerPixel) {
446 if (!bitsPerPixel) return E_POINTER;
447 *bitsPerPixel = mBitsPerPixel;
448 LogFlow(("FFmpeg::COMGETTER(BitsPerPixel): returning depth %lu\n",
449 (unsigned long) *bitsPerPixel));
450 return S_OK;
451}
452
453/**
454 * Return the number of bytes per line in our frame buffer.
455 *
456 * @returns COM status code
457 * @retval bytesPerLine The number of bytes per line
458 */
459STDMETHODIMP VNCFB::COMGETTER(BytesPerLine) (ULONG *bytesPerLine) {
460 if (!bytesPerLine) return E_POINTER;
461 LogFlow(("FFmpeg::COMGETTER(BytesPerLine): returning line size %lu\n", (unsigned long) mBytesPerLine));
462 *bytesPerLine = mBytesPerLine;
463 return S_OK;
464}
465
466/**
467 * Return the pixel layout of our frame buffer.
468 *
469 * @returns COM status code
470 * @retval pixelFormat The pixel layout
471 */
472STDMETHODIMP VNCFB::COMGETTER(PixelFormat) (ULONG *pixelFormat) {
473 if (!pixelFormat) return E_POINTER;
474 LogFlow(("FFmpeg::COMGETTER(PixelFormat): returning pixel format: %lu\n", (unsigned long) mPixelFormat));
475 *pixelFormat = mPixelFormat;
476 return S_OK;
477}
478
479/**
480 * Return whether we use the guest VRAM directly.
481 *
482 * @returns COM status code
483 * @retval pixelFormat The pixel layout
484 */
485STDMETHODIMP VNCFB::COMGETTER(UsesGuestVRAM) (BOOL *usesGuestVRAM) {
486 if (!usesGuestVRAM) return E_POINTER;
487 LogFlow(("FFmpeg::COMGETTER(UsesGuestVRAM): uses guest VRAM? %d\n", mRGBBuffer == NULL));
488 *usesGuestVRAM = (mRGBBuffer == NULL);
489 return S_OK;
490}
491
492/**
493 * Return the number of lines of our frame buffer which can not be used
494 * (e.g. for status lines etc?).
495 *
496 * @returns COM status code
497 * @retval heightReduction The number of unused lines
498 */
499STDMETHODIMP VNCFB::COMGETTER(HeightReduction) (ULONG *heightReduction) {
500 if (!heightReduction) return E_POINTER;
501 /* no reduction */
502 *heightReduction = 0;
503 LogFlow(("FFmpeg::COMGETTER(HeightReduction): returning 0\n"));
504 return S_OK;
505}
506
507/**
508 * Return a pointer to the alpha-blended overlay used to render status icons
509 * etc above the framebuffer.
510 *
511 * @returns COM status code
512 * @retval aOverlay The overlay framebuffer
513 */
514STDMETHODIMP VNCFB::COMGETTER(Overlay) (IFramebufferOverlay **aOverlay) {
515 if (!aOverlay) return E_POINTER;
516 /* not yet implemented */
517 *aOverlay = 0;
518 LogFlow(("FFmpeg::COMGETTER(Overlay): returning 0\n"));
519 return S_OK;
520}
521
522/**
523 * Return id of associated window
524 *
525 * @returns COM status code
526 * @retval winId Associated window id
527 */
528STDMETHODIMP VNCFB::COMGETTER(WinId) (ULONG64 *winId) {
529 if (!winId) return E_POINTER;
530 *winId = 0;
531 return S_OK;
532}
533
534// IFramebuffer methods
535/////////////////////////////////////////////////////////////////////////////
536
537STDMETHODIMP VNCFB::Lock() {
538 LogFlow(("VNCFB::Lock: called\n"));
539 int rc = RTCritSectEnter(&mCritSect);
540 AssertRC(rc);
541 if (rc == VINF_SUCCESS) return S_OK;
542 return E_UNEXPECTED;
543}
544
545STDMETHODIMP VNCFB::Unlock() {
546 LogFlow(("VNCFB::Unlock: called\n"));
547 RTCritSectLeave(&mCritSect);
548 return S_OK;
549}
550
551
552/**
553 * Returns whether we like the given video mode.
554 *
555 * @returns COM status code
556 */
557STDMETHODIMP VNCFB::VideoModeSupported(ULONG width, ULONG height, ULONG bpp, BOOL *supported) {
558 if (!supported) return E_POINTER;
559 *supported = true;
560 return S_OK;
561}
562
563/** Stubbed */
564STDMETHODIMP VNCFB::GetVisibleRegion(BYTE *rectangles, ULONG /* count */, ULONG * /* countCopied */) {
565 if (!rectangles) return E_POINTER;
566 *rectangles = 0;
567 return S_OK;
568}
569
570/** Stubbed */
571STDMETHODIMP VNCFB::SetVisibleRegion(BYTE *rectangles, ULONG /* count */) {
572 if (!rectangles) return E_POINTER;
573 return S_OK;
574}
575
576STDMETHODIMP VNCFB::ProcessVHWACommand(BYTE *pCommand) {
577 return E_NOTIMPL;
578}
579
580#ifdef VBOX_WITH_XPCOM
581NS_DECL_CLASSINFO(VNCFB)
582NS_IMPL_THREADSAFE_ISUPPORTS1_CI(VNCFB, IFramebuffer)
583#endif
584
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