VirtualBox

source: vbox/trunk/src/VBox/Frontends/VBoxSDL/Framebuffer.cpp@ 3832

Last change on this file since 3832 was 3761, checked in by vboxsync, 18 years ago

Main/Frontends: Cleaned up IFramebuffer interface.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 45.2 KB
Line 
1/** @file
2 *
3 * VBox frontends: VBoxSDL (simple frontend based on SDL):
4 * Implementation of VBoxSDLFB (SDL framebuffer) class
5 */
6
7/*
8 * Copyright (C) 2006-2007 innotek GmbH
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License as published by the Free Software Foundation,
14 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
15 * distribution. VirtualBox OSE is distributed in the hope that it will
16 * be useful, but WITHOUT ANY WARRANTY of any kind.
17 *
18 * If you received this file as part of a commercial VirtualBox
19 * distribution, then only the terms of your commercial VirtualBox
20 * license agreement apply instead of the previous paragraph.
21 */
22
23#include <VBox/com/com.h>
24#include <VBox/com/string.h>
25#include <VBox/com/Guid.h>
26#include <VBox/com/ErrorInfo.h>
27#include <VBox/com/EventQueue.h>
28#include <VBox/com/VirtualBox.h>
29
30#include <iprt/stream.h>
31
32#ifdef RT_OS_OS2
33# undef RT_MAX
34// from <iprt/cdefs.h>
35# define RT_MAX(Value1, Value2) ((Value1) >= (Value2) ? (Value1) : (Value2))
36#endif
37
38using namespace com;
39
40#define LOG_GROUP LOG_GROUP_GUI
41#include <VBox/err.h>
42#include <VBox/log.h>
43#include <stdlib.h>
44#include <signal.h>
45
46#include "VBoxSDL.h"
47#include "Framebuffer.h"
48#include "Ico64x01.h"
49
50#if defined(VBOX_WITH_XPCOM)
51NS_IMPL_ISUPPORTS1_CI(VBoxSDLFB, IFramebuffer)
52NS_DECL_CLASSINFO(VBoxSDLFB)
53NS_IMPL_ISUPPORTS1_CI(VBoxSDLFBOverlay, IFramebufferOverlay)
54NS_DECL_CLASSINFO(VBoxSDLFBOverlay)
55#endif
56
57#ifdef VBOX_SECURELABEL
58/* function pointers */
59extern "C"
60{
61DECLSPEC int (SDLCALL *pTTF_Init)(void);
62DECLSPEC TTF_Font* (SDLCALL *pTTF_OpenFont)(const char *file, int ptsize);
63DECLSPEC SDL_Surface* (SDLCALL *pTTF_RenderUTF8_Solid)(TTF_Font *font, const char *text, SDL_Color fg);
64DECLSPEC void (SDLCALL *pTTF_CloseFont)(TTF_Font *font);
65DECLSPEC void (SDLCALL *pTTF_Quit)(void);
66}
67#endif /* VBOX_SECURELABEL */
68
69//
70// Constructor / destructor
71//
72
73/**
74 * SDL framebuffer constructor. It is called from the main
75 * (i.e. SDL) thread. Therefore it is safe to use SDL calls
76 * here.
77 * @param fFullscreen flag whether we start in fullscreen mode
78 * @param fResizable flag whether the SDL window should be resizable
79 * @param fShowSDLConfig flag whether we print out SDL settings
80 * @param iFixedWidth fixed SDL width (-1 means not set)
81 * @param iFixedHeight fixed SDL height (-1 means not set)
82 */
83VBoxSDLFB::VBoxSDLFB(bool fFullscreen, bool fResizable, bool fShowSDLConfig,
84 uint32_t u32FixedWidth, uint32_t u32FixedHeight, uint32_t u32FixedBPP)
85{
86 int rc;
87 LogFlow(("VBoxSDLFB::VBoxSDLFB\n"));
88
89#if defined (RT_OS_WINDOWS)
90 refcnt = 0;
91#endif
92
93 mScreen = NULL;
94 mSurfVRAM = NULL;
95 mfInitialized = false;
96 mfFullscreen = fFullscreen;
97 mTopOffset = 0;
98 mfResizable = fResizable;
99 mfShowSDLConfig = fShowSDLConfig;
100 mFixedSDLWidth = u32FixedWidth;
101 mFixedSDLHeight = u32FixedHeight;
102 mFixedSDLBPP = u32FixedBPP;
103 mDefaultSDLBPP = 32;
104 mCenterXOffset = 0;
105 mCenterYOffset = 0;
106 /* Start with standard screen dimensions. */
107 mGuestXRes = 640;
108 mGuestYRes = 480;
109 mPixelFormat = FramebufferPixelFormat_PixelFormatOpaque;
110 mUsesGuestVRAM = FALSE;
111 mPtrVRAM = NULL;
112 mBitsPerPixel = 0;
113 mBytesPerLine = 0;
114#ifdef VBOX_SECURELABEL
115 mLabelFont = NULL;
116 mLabelHeight = 0;
117#endif
118 mWMIcon = NULL;
119
120 /* memorize the thread that inited us, that's the SDL thread */
121 mSdlNativeThread = RTThreadNativeSelf();
122
123 rc = RTCritSectInit(&mUpdateLock);
124 AssertMsg(rc == VINF_SUCCESS, ("Error from RTCritSectInit!\n"));
125
126#ifdef RT_OS_WINDOWS
127 /* default to DirectX if nothing else set */
128 if (!getenv("SDL_VIDEODRIVER"))
129 {
130 _putenv("SDL_VIDEODRIVER=directx");
131// _putenv("SDL_VIDEODRIVER=windib");
132 }
133#endif
134#ifdef RT_OS_LINUX
135 /* On some X servers the mouse is stuck inside the bottom right corner.
136 * See http://wiki.clug.org.za/wiki/QEMU_mouse_not_working */
137 setenv("SDL_VIDEO_X11_DGAMOUSE", "0", 1);
138#endif
139 rc = SDL_InitSubSystem(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_NOPARACHUTE);
140 if (rc != 0)
141 {
142 RTPrintf("SDL Error: '%s'\n", SDL_GetError());
143 return;
144 }
145
146#ifdef RT_OS_LINUX
147 /* NOTE: we still want Ctrl-C to work, so we undo the SDL redirections */
148 signal(SIGINT, SIG_DFL);
149 signal(SIGQUIT, SIG_DFL);
150#endif
151
152 const SDL_VideoInfo *videoInfo = SDL_GetVideoInfo();
153 Assert(videoInfo);
154 if (videoInfo)
155 {
156 switch (videoInfo->vfmt->BitsPerPixel)
157 {
158 case 16: mDefaultSDLBPP = 16; break;
159 case 24: mDefaultSDLBPP = 24; break;
160 default:
161 case 32: mDefaultSDLBPP = 32; break;
162 }
163
164 /* output what SDL is capable of */
165 if (mfShowSDLConfig)
166 RTPrintf("SDL capabilities:\n"
167 " Hardware surface support: %s\n"
168 " Window manager available: %s\n"
169 " Screen to screen blits accelerated: %s\n"
170 " Screen to screen colorkey blits accelerated: %s\n"
171 " Screen to screen alpha blits accelerated: %s\n"
172 " Memory to screen blits accelerated: %s\n"
173 " Memory to screen colorkey blits accelerated: %s\n"
174 " Memory to screen alpha blits accelerated: %s\n"
175 " Color fills accelerated: %s\n"
176 " Video memory in kilobytes: %d\n"
177 " Optimal bpp mode: %d\n"
178 "SDL video driver: %s\n",
179 videoInfo->hw_available ? "yes" : "no",
180 videoInfo->wm_available ? "yes" : "no",
181 videoInfo->blit_hw ? "yes" : "no",
182 videoInfo->blit_hw_CC ? "yes" : "no",
183 videoInfo->blit_hw_A ? "yes" : "no",
184 videoInfo->blit_sw ? "yes" : "no",
185 videoInfo->blit_sw_CC ? "yes" : "no",
186 videoInfo->blit_sw_A ? "yes" : "no",
187 videoInfo->blit_fill ? "yes" : "no",
188 videoInfo->video_mem,
189 videoInfo->vfmt->BitsPerPixel,
190 getenv("SDL_VIDEODRIVER"));
191 }
192
193 if (12320 == g_cbIco64x01)
194 {
195 mWMIcon = SDL_AllocSurface(SDL_SWSURFACE, 64, 64, 24, 0xff, 0xff00, 0xff0000, 0);
196 /** @todo make it as simple as possible. No PNM interpreter here... */
197 if (mWMIcon)
198 {
199 memcpy(mWMIcon->pixels, g_abIco64x01+32, g_cbIco64x01-32);
200 SDL_WM_SetIcon(mWMIcon, NULL);
201 }
202 }
203
204 resizeGuest();
205 Assert(mScreen);
206 mfInitialized = true;
207}
208
209VBoxSDLFB::~VBoxSDLFB()
210{
211 LogFlow(("VBoxSDLFB::~VBoxSDLFB\n"));
212 RTCritSectDelete(&mUpdateLock);
213}
214
215
216/**
217 * Returns the current framebuffer width in pixels.
218 *
219 * @returns COM status code
220 * @param width Address of result buffer.
221 */
222STDMETHODIMP VBoxSDLFB::COMGETTER(Width)(ULONG *width)
223{
224 LogFlow(("VBoxSDLFB::GetWidth\n"));
225 if (!width)
226 return E_INVALIDARG;
227 *width = mGuestXRes;
228 return S_OK;
229}
230
231/**
232 * Returns the current framebuffer height in pixels.
233 *
234 * @returns COM status code
235 * @param height Address of result buffer.
236 */
237STDMETHODIMP VBoxSDLFB::COMGETTER(Height)(ULONG *height)
238{
239 LogFlow(("VBoxSDLFB::GetHeight\n"));
240 if (!height)
241 return E_INVALIDARG;
242 *height = mGuestYRes;
243 return S_OK;
244}
245
246/**
247 * Lock the framebuffer (make its address immutable).
248 *
249 * @returns COM status code
250 */
251STDMETHODIMP VBoxSDLFB::Lock()
252{
253 LogFlow(("VBoxSDLFB::Lock\n"));
254 RTCritSectEnter(&mUpdateLock);
255 return S_OK;
256}
257
258/**
259 * Unlock the framebuffer.
260 *
261 * @returns COM status code
262 */
263STDMETHODIMP VBoxSDLFB::Unlock()
264{
265 LogFlow(("VBoxSDLFB::Unlock\n"));
266 RTCritSectLeave(&mUpdateLock);
267 return S_OK;
268}
269
270/**
271 * Return the framebuffer start address.
272 *
273 * @returns COM status code.
274 * @param address Pointer to result variable.
275 */
276STDMETHODIMP VBoxSDLFB::COMGETTER(Address)(BYTE **address)
277{
278 LogFlow(("VBoxSDLFB::GetAddress\n"));
279 if (!address)
280 return E_INVALIDARG;
281
282 if (mSurfVRAM)
283 {
284 *address = (BYTE *) mSurfVRAM->pixels;
285 }
286 else
287 {
288 /* That's actually rather bad. */
289 AssertMsgFailed(("mSurfVRAM is NULL!\n"));
290 return E_FAIL;
291 }
292 LogFlow(("VBoxSDL::GetAddress returning %p\n", *address));
293 return S_OK;
294}
295
296/**
297 * Return the current framebuffer color depth.
298 *
299 * @returns COM status code
300 * @param bitsPerPixel Address of result variable
301 */
302STDMETHODIMP VBoxSDLFB::COMGETTER(BitsPerPixel)(ULONG *bitsPerPixel)
303{
304 LogFlow(("VBoxSDLFB::GetBitsPerPixel\n"));
305 if (!bitsPerPixel)
306 return E_INVALIDARG;
307 /* get the information directly from the surface in use */
308 Assert(mSurfVRAM);
309 *bitsPerPixel = (ULONG)(mSurfVRAM ? mSurfVRAM->format->BitsPerPixel : 0);
310 return S_OK;
311}
312
313/**
314 * Return the current framebuffer line size in bytes.
315 *
316 * @returns COM status code.
317 * @param lineSize Address of result variable.
318 */
319STDMETHODIMP VBoxSDLFB::COMGETTER(BytesPerLine)(ULONG *bytesPerLine)
320{
321 LogFlow(("VBoxSDLFB::GetBytesPerLine\n"));
322 if (!bytesPerLine)
323 return E_INVALIDARG;
324 /* get the information directly from the surface */
325 Assert(mSurfVRAM);
326 *bytesPerLine = (ULONG)(mSurfVRAM ? mSurfVRAM->pitch : 0);
327 return S_OK;
328}
329
330STDMETHODIMP VBoxSDLFB::COMGETTER(PixelFormat) (ULONG *pixelFormat)
331{
332 if (!pixelFormat)
333 return E_POINTER;
334 *pixelFormat = mPixelFormat;
335 return S_OK;
336}
337
338STDMETHODIMP VBoxSDLFB::COMGETTER(UsesGuestVRAM) (BOOL *usesGuestVRAM)
339{
340 if (!usesGuestVRAM)
341 return E_POINTER;
342 *usesGuestVRAM = mUsesGuestVRAM;
343 return S_OK;
344}
345
346/**
347 * Returns by how many pixels the guest should shrink its
348 * video mode height values.
349 *
350 * @returns COM status code.
351 * @param heightReduction Address of result variable.
352 */
353STDMETHODIMP VBoxSDLFB::COMGETTER(HeightReduction)(ULONG *heightReduction)
354{
355 if (!heightReduction)
356 return E_POINTER;
357#ifdef VBOX_SECURELABEL
358 *heightReduction = mLabelHeight;
359#else
360 *heightReduction = 0;
361#endif
362 return S_OK;
363}
364
365/**
366 * Returns a pointer to an alpha-blended overlay used for displaying status
367 * icons above the framebuffer.
368 *
369 * @returns COM status code.
370 * @param aOverlay The overlay framebuffer.
371 */
372STDMETHODIMP VBoxSDLFB::COMGETTER(Overlay)(IFramebufferOverlay **aOverlay)
373{
374 if (!aOverlay)
375 return E_POINTER;
376 /* Not yet implemented */
377 *aOverlay = 0;
378 return S_OK;
379}
380
381/**
382 * Notify framebuffer of an update.
383 *
384 * @returns COM status code
385 * @param x Update region upper left corner x value.
386 * @param y Update region upper left corner y value.
387 * @param w Update region width in pixels.
388 * @param h Update region height in pixels.
389 * @param finished Address of output flag whether the update
390 * could be fully processed in this call (which
391 * has to return immediately) or VBox should wait
392 * for a call to the update complete API before
393 * continuing with display updates.
394 */
395STDMETHODIMP VBoxSDLFB::NotifyUpdate(ULONG x, ULONG y,
396 ULONG w, ULONG h, BOOL *finished)
397{
398 /*
399 * The input values are in guest screen coordinates.
400 */
401 LogFlow(("VBoxSDLFB::NotifyUpdate: x = %d, y = %d, w = %d, h = %d\n",
402 x, y, w, h));
403
404#ifdef RT_OS_LINUX
405 /*
406 * SDL does not allow us to make this call from any other thread than
407 * the main SDL thread (which initialized the video mode). So we have
408 * to send an event to the main SDL thread and process it there. For
409 * sake of simplicity, we encode all information in the event parameters.
410 */
411 SDL_Event event;
412 event.type = SDL_USEREVENT;
413 event.user.type = SDL_USER_EVENT_UPDATERECT;
414 // 16 bit is enough for coordinates
415 event.user.data1 = (void*)(x << 16 | y);
416 event.user.data2 = (void*)(w << 16 | h);
417 PushNotifyUpdateEvent(&event);
418#else /* !RT_OS_LINUX */
419 update(x, y, w, h, true /* fGuestRelative */);
420#endif /* !RT_OS_LINUX */
421
422 /*
423 * The Display thread can continue as we will lock the framebuffer
424 * from the SDL thread when we get to actually doing the update.
425 */
426 if (finished)
427 *finished = TRUE;
428 return S_OK;
429}
430
431/**
432 * Request a display resize from the framebuffer.
433 *
434 * @returns COM status code.
435 * @param pixelFormat The requested pixel format.
436 * @param vram Pointer to the guest VRAM buffer (can be NULL).
437 * @param bitsPerPixel Color depth in bits.
438 * @param bytesPerLine Size of a scanline in bytes.
439 * @param w New display width in pixels.
440 * @param h New display height in pixels.
441 * @param finished Address of output flag whether the update
442 * could be fully processed in this call (which
443 * has to return immediately) or VBox should wait
444 * for all call to the resize complete API before
445 * continuing with display updates.
446 */
447STDMETHODIMP VBoxSDLFB::RequestResize(ULONG aScreenId, ULONG pixelFormat, BYTE *vram,
448 ULONG bitsPerPixel, ULONG bytesPerLine,
449 ULONG w, ULONG h, BOOL *finished)
450{
451 LogFlowFunc (("w=%d, h=%d, pixelFormat=0x%08lX, vram=%p, "
452 "bpp=%d, bpl=%d\n",
453 w, h, pixelFormat, vram, bitsPerPixel, bytesPerLine));
454
455 /*
456 * SDL does not allow us to make this call from any other thread than
457 * the main thread (the one which initialized the video mode). So we
458 * have to send an event to the main SDL thread and tell VBox to wait.
459 */
460 if (!finished)
461 {
462 AssertMsgFailed(("RequestResize requires the finished flag!\n"));
463 return E_FAIL;
464 }
465
466 mGuestXRes = w;
467 mGuestYRes = h;
468 mPixelFormat = pixelFormat;
469 mPtrVRAM = vram;
470 mBitsPerPixel = bitsPerPixel;
471 mBytesPerLine = bytesPerLine;
472 mUsesGuestVRAM = FALSE; /* yet */
473
474 SDL_Event event;
475 event.type = SDL_USEREVENT;
476 event.user.type = SDL_USER_EVENT_RESIZE;
477
478 /* Try multiple times if necessary */
479 PushSDLEventForSure(&event);
480
481 /* we want this request to be processed quickly, so yield the CPU */
482 RTThreadYield();
483
484 *finished = false;
485
486 return S_OK;
487}
488
489/**
490 * Returns which acceleration operations are supported
491 *
492 * @returns COM status code
493 * @param operation acceleration operation code
494 * @supported result
495 */
496STDMETHODIMP VBoxSDLFB::OperationSupported(FramebufferAccelerationOperation_T operation, BOOL *supported)
497{
498 if (!supported)
499 return E_POINTER;
500
501 // SDL gives us software surfaces, futile
502 *supported = false;
503#if 0
504 switch (operation)
505 {
506 case FramebufferAccelerationOperation_SolidFillAcceleration:
507 *supported = true;
508 break;
509 case FramebufferAccelerationOperation_ScreenCopyAcceleration:
510 *supported = true;
511 break;
512 default:
513 *supported = false;
514 }
515#endif
516 return S_OK;
517}
518
519/**
520 * Returns whether we like the given video mode.
521 *
522 * @returns COM status code
523 * @param width video mode width in pixels
524 * @param height video mode height in pixels
525 * @param bpp video mode bit depth in bits per pixel
526 * @param supported pointer to result variable
527 */
528STDMETHODIMP VBoxSDLFB::VideoModeSupported(ULONG width, ULONG height, ULONG bpp, BOOL *supported)
529{
530 if (!supported)
531 return E_POINTER;
532
533 /* are constraints set? */
534 if ( ( (mMaxScreenWidth != ~(uint32_t)0)
535 && (width > mMaxScreenWidth)
536 || ( (mMaxScreenHeight != ~(uint32_t)0)
537 && (height > mMaxScreenHeight))))
538 {
539 /* nope, we don't want that (but still don't freak out if it is set) */
540#ifdef DEBUG
541 printf("VBoxSDL::VideoModeSupported: we refused mode %dx%dx%d\n", width, height, bpp);
542#endif
543 *supported = false;
544 }
545 else
546 {
547 /* anything will do */
548 *supported = true;
549 }
550 return S_OK;
551}
552
553STDMETHODIMP VBoxSDLFB::SolidFill(ULONG x, ULONG y, ULONG width, ULONG height,
554 ULONG color, BOOL *handled)
555{
556 if (!handled)
557 return E_POINTER;
558 // SDL gives us software surfaces, futile
559#if 0
560 printf("SolidFill: x: %d, y: %d, w: %d, h: %d, color: %d\n", x, y, width, height, color);
561 SDL_Rect rect = { (Sint16)x, (Sint16)y, (Sint16)width, (Sint16)height };
562 SDL_FillRect(mScreen, &rect, color);
563 //SDL_UpdateRect(mScreen, x, y, width, height);
564 *handled = true;
565#else
566 *handled = false;
567#endif
568 return S_OK;
569}
570
571STDMETHODIMP VBoxSDLFB::CopyScreenBits(ULONG xDst, ULONG yDst, ULONG xSrc, ULONG ySrc,
572 ULONG width, ULONG height, BOOL *handled)
573{
574 if (!handled)
575 return E_POINTER;
576 // SDL gives us software surfaces, futile
577#if 0
578 SDL_Rect srcRect = { (Sint16)xSrc, (Sint16)ySrc, (Sint16)width, (Sint16)height };
579 SDL_Rect dstRect = { (Sint16)xDst, (Sint16)yDst, (Sint16)width, (Sint16)height };
580 SDL_BlitSurface(mScreen, &srcRect, mScreen, &dstRect);
581 *handled = true;
582#else
583 *handled = false;
584#endif
585 return S_OK;
586}
587
588STDMETHODIMP VBoxSDLFB::GetVisibleRegion(BYTE *aRectangles, ULONG aCount,
589 ULONG *aCountCopied)
590{
591 PRTRECT rects = (PRTRECT)aRectangles;
592
593 if (!rects)
594 return E_POINTER;
595
596 /// @todo
597
598 NOREF(aCount);
599 NOREF(aCountCopied);
600
601 return S_OK;
602}
603
604STDMETHODIMP VBoxSDLFB::SetVisibleRegion(BYTE *aRectangles, ULONG aCount)
605{
606 PRTRECT rects = (PRTRECT)aRectangles;
607
608 if (!rects)
609 return E_POINTER;
610
611 /// @todo
612
613 NOREF(aCount);
614
615 return S_OK;
616}
617
618//
619// Internal public methods
620//
621
622/**
623 * Method that does the actual resize of the guest framebuffer and
624 * then changes the SDL framebuffer setup.
625 */
626void VBoxSDLFB::resizeGuest()
627{
628 LogFlowFunc (("mGuestXRes: %d, mGuestYRes: %d\n", mGuestXRes, mGuestYRes));
629 AssertMsg(mSdlNativeThread == RTThreadNativeSelf(),
630 ("Wrong thread! SDL is not threadsafe!\n"));
631
632 uint32_t Rmask, Gmask, Bmask, Amask = 0;
633
634 mUsesGuestVRAM = FALSE;
635
636 /* pixel characteristics. if we don't support the format directly, we will
637 * fallback to the indirect 32bpp buffer (mUsesGuestVRAM will remain
638 * FALSE) */
639 if (mPixelFormat == FramebufferPixelFormat_FOURCC_RGB)
640 {
641 switch (mBitsPerPixel)
642 {
643 case 16:
644 case 24:
645 case 32:
646 mUsesGuestVRAM = TRUE;
647 break;
648 default:
649 /* the fallback buffer is always 32bpp */
650 mBitsPerPixel = 32;
651 mBytesPerLine = mGuestXRes * 4;
652 break;
653 }
654 }
655 else
656 {
657 /* the fallback buffer is always RGB, 32bpp */
658 mPixelFormat = FramebufferPixelFormat_FOURCC_RGB;
659 mBitsPerPixel = 32;
660 mBytesPerLine = mGuestXRes * 4;
661 }
662
663 switch (mBitsPerPixel)
664 {
665 case 16: Rmask = 0x0000F800; Gmask = 0x000007E0; Bmask = 0x0000001F; break;
666 default: Rmask = 0x00FF0000; Gmask = 0x0000FF00; Bmask = 0x000000FF; break;
667 }
668
669 /* first free the current surface */
670 if (mSurfVRAM)
671 {
672 SDL_FreeSurface(mSurfVRAM);
673 mSurfVRAM = NULL;
674 }
675
676 /* is the guest in a linear framebuffer mode we support? */
677 if (mUsesGuestVRAM)
678 {
679
680 /* Create a source surface from guest VRAM. */
681 mSurfVRAM = SDL_CreateRGBSurfaceFrom(mPtrVRAM, mGuestXRes, mGuestYRes, mBitsPerPixel,
682 mBytesPerLine, Rmask, Gmask, Bmask, Amask);
683 }
684 else
685 {
686 /* Create a software surface for which SDL allocates the RAM */
687 mSurfVRAM = SDL_CreateRGBSurface(SDL_SWSURFACE, mGuestXRes, mGuestYRes, mBitsPerPixel,
688 Rmask, Gmask, Bmask, Amask);
689 }
690 LogFlow(("VBoxSDL:: created VRAM surface %p\n", mSurfVRAM));
691
692 /* now adjust the SDL resolution */
693 resizeSDL();
694}
695
696/**
697 * Sets SDL video mode. This is independent from guest video
698 * mode changes.
699 *
700 * @remarks Must be called from the SDL thread!
701 */
702void VBoxSDLFB::resizeSDL(void)
703{
704 LogFlow(("VBoxSDL:resizeSDL\n"));
705
706 /*
707 * We request a hardware surface from SDL so that we can perform
708 * accelerated system memory to VRAM blits. The way video handling
709 * works it that on the one hand we have the screen surface from SDL
710 * and on the other hand we have a software surface that we create
711 * using guest VRAM memory for linear modes and using SDL allocated
712 * system memory for text and non linear graphics modes. We never
713 * directly write to the screen surface but always use SDL blitting
714 * functions to blit from our system memory surface to the VRAM.
715 * Therefore, SDL can take advantage of hardware acceleration.
716 */
717 int sdlFlags = SDL_HWSURFACE | SDL_ASYNCBLIT | SDL_HWACCEL;
718 if (mfResizable)
719 sdlFlags |= SDL_RESIZABLE;
720 if (mfFullscreen)
721 sdlFlags |= SDL_FULLSCREEN;
722
723 /*
724 * Now we have to check whether there are video mode restrictions
725 */
726 SDL_Rect **modes;
727 /* Get available fullscreen/hardware modes */
728 modes = SDL_ListModes(NULL, sdlFlags);
729 Assert(modes != NULL);
730 /* -1 means that any mode is possible (usually non fullscreen) */
731 if (modes != (SDL_Rect **)-1)
732 {
733 /*
734 * according to the SDL documentation, the API guarantees that
735 * the modes are sorted from larger to smaller, so we just
736 * take the first entry as the maximum.
737 */
738 mMaxScreenWidth = modes[0]->w;
739 mMaxScreenHeight = modes[0]->h;
740 }
741 else
742 {
743 /* no restriction */
744 mMaxScreenWidth = ~(uint32_t)0;
745 mMaxScreenHeight = ~(uint32_t)0;
746 }
747
748 uint32_t newWidth;
749 uint32_t newHeight;
750
751 /* reset the centering offsets */
752 mCenterXOffset = 0;
753 mCenterYOffset = 0;
754
755 /* we either have a fixed SDL resolution or we take the guest's */
756 if (mFixedSDLWidth != ~(uint32_t)0)
757 {
758 newWidth = mFixedSDLWidth;
759 newHeight = mFixedSDLHeight;
760 }
761 else
762 {
763 newWidth = RT_MIN(mGuestXRes, mMaxScreenWidth);
764#ifdef VBOX_SECURELABEL
765 newHeight = RT_MIN(mGuestYRes + mLabelHeight, mMaxScreenHeight);
766#else
767 newHeight = RT_MIN(mGuestYRes, mMaxScreenHeight);
768#endif
769 }
770
771 /* we don't have any extra space by default */
772 mTopOffset = 0;
773
774 /*
775 * Now set the screen resolution and get the surface pointer
776 * @todo BPP is not supported!
777 */
778 mScreen = SDL_SetVideoMode(newWidth, newHeight, 0, sdlFlags);
779#ifdef VBOX_SECURELABEL
780 /*
781 * For non fixed SDL resolution, the above call tried to add the label height
782 * to the guest height. If it worked, we have an offset. If it didn't the below
783 * code will try again with the original guest resolution.
784 */
785 if (mFixedSDLWidth == ~(uint32_t)0)
786 {
787 /* if it didn't work, then we have to go for the original resolution and paint over the guest */
788 if (!mScreen)
789 {
790 mScreen = SDL_SetVideoMode(newWidth, newHeight - mLabelHeight, 0, sdlFlags);
791 }
792 else
793 {
794 /* we now have some extra space */
795 mTopOffset = mLabelHeight;
796 }
797 }
798 else
799 {
800 /* in case the guest resolution is small enough, we do have a top offset */
801 if (mFixedSDLHeight - mGuestYRes >= mLabelHeight)
802 mTopOffset = mLabelHeight;
803
804 /* we also might have to center the guest picture */
805 if (mFixedSDLWidth > mGuestXRes)
806 mCenterXOffset = (mFixedSDLWidth - mGuestXRes) / 2;
807 if (mFixedSDLHeight > mGuestYRes + mLabelHeight)
808 mCenterYOffset = (mFixedSDLHeight - (mGuestYRes + mLabelHeight)) / 2;
809 }
810#endif
811 AssertMsg(mScreen, ("Error: SDL_SetVideoMode failed!\n"));
812 if (mScreen)
813 {
814#ifdef VBOX_WIN32_UI
815 /* inform the UI code */
816 resizeUI(mScreen->w, mScreen->h);
817#endif
818 if (mfShowSDLConfig)
819 RTPrintf("Resized to %dx%d, screen surface type: %s\n", mScreen->w, mScreen->h,
820 ((mScreen->flags & SDL_HWSURFACE) == 0) ? "software" : "hardware");
821 }
822 repaint();
823}
824
825/**
826 * Update specified framebuffer area. The coordinates can either be
827 * relative to the guest framebuffer or relative to the screen.
828 *
829 * @remarks Must be called from the SDL thread on Linux!
830 * @param x left column
831 * @param y top row
832 * @param w width in pixels
833 * @param h height in pixels
834 * @param fGuestRelative flag whether the above values are guest relative or screen relative;
835 */
836void VBoxSDLFB::update(int x, int y, int w, int h, bool fGuestRelative)
837{
838#ifdef RT_OS_LINUX
839 AssertMsg(mSdlNativeThread == RTThreadNativeSelf(), ("Wrong thread! SDL is not threadsafe!\n"));
840#endif
841 Assert(mScreen);
842 Assert(mSurfVRAM);
843 if (!mScreen || !mSurfVRAM)
844 return;
845
846 /* the source and destination rectangles */
847 SDL_Rect srcRect;
848 SDL_Rect dstRect;
849
850 /* this is how many pixels we have to cut off from the height for this specific blit */
851 int yCutoffGuest = 0;
852
853#ifdef VBOX_SECURELABEL
854 bool fPaintLabel = false;
855 /* if we have a label and no space for it, we have to cut off a bit */
856 if (mLabelHeight && !mTopOffset)
857 {
858 if (y < (int)mLabelHeight)
859 yCutoffGuest = mLabelHeight - y;
860 }
861#endif
862
863 /**
864 * If we get a SDL window relative update, we
865 * just perform a full screen update to keep things simple.
866 *
867 * @todo improve
868 */
869 if (!fGuestRelative)
870 {
871#ifdef VBOX_SECURELABEL
872 /* repaint the label if necessary */
873 if (y < (int)mLabelHeight)
874 fPaintLabel = true;
875#endif
876 x = 0;
877 w = mGuestXRes;
878 y = 0;
879 h = mGuestYRes;
880 }
881
882 srcRect.x = x;
883 srcRect.y = y + yCutoffGuest;
884 srcRect.w = w;
885 srcRect.h = RT_MAX(0, h - yCutoffGuest);
886
887 /*
888 * Destination rectangle is just offset by the label height.
889 * There are two cases though: label height is added to the
890 * guest resolution (mTopOffset == mLabelHeight; yCutoffGuest == 0)
891 * or the label cuts off a portion of the guest screen (mTopOffset == 0;
892 * yCutoffGuest >= 0)
893 */
894 dstRect.x = x + mCenterXOffset;
895#ifdef VBOX_SECURELABEL
896 dstRect.y = RT_MAX(mLabelHeight, y + yCutoffGuest + mTopOffset) + mCenterYOffset;
897#else
898 dstRect.y = y + yCutoffGuest + mTopOffset + mCenterYOffset;
899#endif
900 dstRect.w = w;
901 dstRect.h = RT_MAX(0, h - yCutoffGuest);
902
903 //RTPrintf("y = %d h = %d mapped to srcY %d srcH %d mapped to dstY = %d dstH %d (guestrel: %d, mLabelHeight: %d, mTopOffset: %d)\n",
904 // y, h, srcRect.y, srcRect.h, dstRect.y, dstRect.h, fGuestRelative, mLabelHeight, mTopOffset);
905
906 /*
907 * Now we just blit
908 */
909 SDL_BlitSurface(mSurfVRAM, &srcRect, mScreen, &dstRect);
910 /* hardware surfaces don't need update notifications */
911 if ((mScreen->flags & SDL_HWSURFACE) == 0)
912 SDL_UpdateRect(mScreen, dstRect.x, dstRect.y, dstRect.w, dstRect.h);
913
914#ifdef VBOX_SECURELABEL
915 if (fPaintLabel)
916 paintSecureLabel(0, 0, 0, 0, false);
917#endif
918}
919
920/**
921 * Repaint the whole framebuffer
922 *
923 * @remarks Must be called from the SDL thread!
924 */
925void VBoxSDLFB::repaint()
926{
927 AssertMsg(mSdlNativeThread == RTThreadNativeSelf(), ("Wrong thread! SDL is not threadsafe!\n"));
928 LogFlow(("VBoxSDLFB::repaint\n"));
929 update(0, 0, mScreen->w, mScreen->h, false /* fGuestRelative */);
930}
931
932bool VBoxSDLFB::getFullscreen()
933{
934 LogFlow(("VBoxSDLFB::getFullscreen\n"));
935 return mfFullscreen;
936}
937
938/**
939 * Toggle fullscreen mode
940 *
941 * @remarks Must be called from the SDL thread!
942 */
943void VBoxSDLFB::setFullscreen(bool fFullscreen)
944{
945 AssertMsg(mSdlNativeThread == RTThreadNativeSelf(), ("Wrong thread! SDL is not threadsafe!\n"));
946 LogFlow(("VBoxSDLFB::SetFullscreen: fullscreen: %d\n", fFullscreen));
947 mfFullscreen = fFullscreen;
948 /* only change the SDL resolution, do not touch the guest framebuffer */
949 resizeSDL();
950}
951
952
953/**
954 * Returns the current x offset of the start of the guest screen
955 *
956 * @returns current x offset in pixels
957 */
958int VBoxSDLFB::getXOffset()
959{
960 /* there can only be an offset for centering */
961 return mCenterXOffset;
962}
963
964/**
965 * Returns the current y offset of the start of the guest screen
966 *
967 * @returns current y offset in pixels
968 */
969int VBoxSDLFB::getYOffset()
970{
971 /* we might have a top offset and a center offset */
972 return mTopOffset + mCenterYOffset;
973}
974
975#ifdef VBOX_SECURELABEL
976/**
977 * Setup the secure labeling parameters
978 *
979 * @returns VBox status code
980 * @param height height of the secure label area in pixels
981 * @param font file path fo the TrueType font file
982 * @param pointsize font size in points
983 */
984int VBoxSDLFB::initSecureLabel(uint32_t height, char *font, uint32_t pointsize)
985{
986 LogFlow(("VBoxSDLFB:initSecureLabel: new offset: %d pixels, new font: %s, new pointsize: %d\n",
987 height, font, pointsize));
988 mLabelHeight = height;
989 Assert(font);
990 pTTF_Init();
991 mLabelFont = pTTF_OpenFont(font, pointsize);
992 if (!mLabelFont)
993 {
994 AssertMsgFailed(("Failed to open TTF font file %s\n", font));
995 return VERR_OPEN_FAILED;
996 }
997 mSecureLabelColorFG = 0x0000FF00;
998 mSecureLabelColorBG = 0x00FFFF00;
999 repaint();
1000 return VINF_SUCCESS;
1001}
1002
1003/**
1004 * Set the secure label text and repaint the label
1005 *
1006 * @param text UTF-8 string of new label
1007 * @remarks must be called from the SDL thread!
1008 */
1009void VBoxSDLFB::setSecureLabelText(const char *text)
1010{
1011 mSecureLabelText = text;
1012 paintSecureLabel(0, 0, 0, 0, true);
1013}
1014
1015/**
1016 * Sets the secure label background color.
1017 *
1018 * @param colorFG encoded RGB value for text
1019 * @param colorBG encored RGB value for background
1020 * @remarks must be called from the SDL thread!
1021 */
1022void VBoxSDLFB::setSecureLabelColor(uint32_t colorFG, uint32_t colorBG)
1023{
1024 mSecureLabelColorFG = colorFG;
1025 mSecureLabelColorBG = colorBG;
1026 paintSecureLabel(0, 0, 0, 0, true);
1027}
1028
1029/**
1030 * Paint the secure label if required
1031 *
1032 * @param fForce Force the repaint
1033 * @remarks must be called from the SDL thread!
1034 */
1035void VBoxSDLFB::paintSecureLabel(int x, int y, int w, int h, bool fForce)
1036{
1037#ifdef RT_OS_LINUX
1038 AssertMsg(mSdlNativeThread == RTThreadNativeSelf(), ("Wrong thread! SDL is not threadsafe!\n"));
1039#endif
1040 /* only when the function is present */
1041 if (!pTTF_RenderUTF8_Solid)
1042 return;
1043 /* check if we can skip the paint */
1044 if (!fForce && ((uint32_t)y > mLabelHeight))
1045 {
1046 return;
1047 }
1048 /* first fill the background */
1049 SDL_Rect rect = {0, 0, (Uint16)mScreen->w, (Uint16)mLabelHeight};
1050 SDL_FillRect(mScreen, &rect, SDL_MapRGB(mScreen->format,
1051 (mSecureLabelColorBG & 0x00FF0000) >> 16, /* red */
1052 (mSecureLabelColorBG & 0x0000FF00) >> 8, /* green */
1053 mSecureLabelColorBG & 0x000000FF)); /* blue */
1054
1055 /* now the text */
1056 if (mLabelFont != NULL && mSecureLabelText)
1057 {
1058 SDL_Color clrFg = {(mSecureLabelColorFG & 0x00FF0000) >> 16,
1059 (mSecureLabelColorFG & 0x0000FF00) >> 8,
1060 mSecureLabelColorFG & 0x000000FF, 0};
1061 SDL_Surface *sText = pTTF_RenderUTF8_Solid(mLabelFont, mSecureLabelText.raw(), clrFg);
1062 rect.x = 10;
1063 SDL_BlitSurface(sText, NULL, mScreen, &rect);
1064 SDL_FreeSurface(sText);
1065 }
1066 /* make sure to update the screen */
1067 SDL_UpdateRect(mScreen, 0, 0, mScreen->w, mLabelHeight);
1068}
1069#endif /* VBOX_SECURELABEL */
1070
1071/**
1072 * Terminate SDL
1073 *
1074 * @remarks must be called from the SDL thread!
1075 */
1076void VBoxSDLFB::uninit()
1077{
1078 AssertMsg(mSdlNativeThread == RTThreadNativeSelf(), ("Wrong thread! SDL is not threadsafe!\n"));
1079 if (mSurfVRAM)
1080 {
1081 SDL_FreeSurface(mSurfVRAM);
1082 mSurfVRAM = NULL;
1083 }
1084 SDL_QuitSubSystem(SDL_INIT_VIDEO);
1085#ifdef VBOX_SECURELABEL
1086 if (mLabelFont)
1087 pTTF_CloseFont(mLabelFont);
1088 if (pTTF_Quit)
1089 pTTF_Quit();
1090#endif
1091 mScreen = NULL;
1092 if (mWMIcon)
1093 {
1094 SDL_FreeSurface(mWMIcon);
1095 mWMIcon = NULL;
1096 }
1097}
1098
1099// IFramebufferOverlay
1100///////////////////////////////////////////////////////////////////////////////////
1101
1102/**
1103 * Constructor for the VBoxSDLFBOverlay class (IFramebufferOverlay implementation)
1104 *
1105 * @param x Initial X offset for the overlay
1106 * @param y Initial Y offset for the overlay
1107 * @param width Initial width for the overlay
1108 * @param height Initial height for the overlay
1109 * @param visible Whether the overlay is initially visible
1110 * @param alpha Initial alpha channel value for the overlay
1111 */
1112VBoxSDLFBOverlay::VBoxSDLFBOverlay(ULONG x, ULONG y, ULONG width, ULONG height,
1113 BOOL visible, VBoxSDLFB *aParent) :
1114 mOverlayX(x), mOverlayY(y), mOverlayWidth(width),
1115 mOverlayHeight(height), mOverlayVisible(visible),
1116 mParent(aParent)
1117{}
1118
1119/**
1120 * Destructor for the VBoxSDLFBOverlay class.
1121 */
1122VBoxSDLFBOverlay::~VBoxSDLFBOverlay()
1123{
1124 SDL_FreeSurface(mBlendedBits);
1125 SDL_FreeSurface(mOverlayBits);
1126}
1127
1128/**
1129 * Perform any initialisation of the overlay that can potentially fail
1130 *
1131 * @returns S_OK on success or the reason for the failure
1132 */
1133HRESULT VBoxSDLFBOverlay::init()
1134{
1135 mBlendedBits = SDL_CreateRGBSurface(SDL_ANYFORMAT, mOverlayWidth, mOverlayHeight, 32,
1136 0x00ff0000, 0x0000ff00, 0x000000ff, 0);
1137 AssertMsgReturn(mBlendedBits != NULL, ("Failed to create an SDL surface\n"),
1138 E_OUTOFMEMORY);
1139 mOverlayBits = SDL_CreateRGBSurface(SDL_SWSURFACE | SDL_SRCALPHA, mOverlayWidth,
1140 mOverlayHeight, 32, 0x00ff0000, 0x0000ff00,
1141 0x000000ff, 0xff000000);
1142 AssertMsgReturn(mOverlayBits != NULL, ("Failed to create an SDL surface\n"),
1143 E_OUTOFMEMORY);
1144 return S_OK;
1145}
1146
1147/**
1148 * Returns the current overlay X offset in pixels.
1149 *
1150 * @returns COM status code
1151 * @param x Address of result buffer.
1152 */
1153STDMETHODIMP VBoxSDLFBOverlay::COMGETTER(X)(ULONG *x)
1154{
1155 LogFlow(("VBoxSDLFBOverlay::GetX\n"));
1156 if (!x)
1157 return E_INVALIDARG;
1158 *x = mOverlayX;
1159 return S_OK;
1160}
1161
1162/**
1163 * Returns the current overlay height in pixels.
1164 *
1165 * @returns COM status code
1166 * @param height Address of result buffer.
1167 */
1168STDMETHODIMP VBoxSDLFBOverlay::COMGETTER(Y)(ULONG *y)
1169{
1170 LogFlow(("VBoxSDLFBOverlay::GetY\n"));
1171 if (!y)
1172 return E_INVALIDARG;
1173 *y = mOverlayY;
1174 return S_OK;
1175}
1176
1177/**
1178 * Returns the current overlay width in pixels. In fact, this returns the line size.
1179 *
1180 * @returns COM status code
1181 * @param width Address of result buffer.
1182 */
1183STDMETHODIMP VBoxSDLFBOverlay::COMGETTER(Width)(ULONG *width)
1184{
1185 LogFlow(("VBoxSDLFBOverlay::GetWidth\n"));
1186 if (!width)
1187 return E_INVALIDARG;
1188 *width = mOverlayBits->pitch;
1189 return S_OK;
1190}
1191
1192/**
1193 * Returns the current overlay line size in pixels.
1194 *
1195 * @returns COM status code
1196 * @param lineSize Address of result buffer.
1197 */
1198STDMETHODIMP VBoxSDLFBOverlay::COMGETTER(BytesPerLine)(ULONG *bytesPerLine)
1199{
1200 LogFlow(("VBoxSDLFBOverlay::GetBytesPerLine\n"));
1201 if (!bytesPerLine)
1202 return E_INVALIDARG;
1203 *bytesPerLine = mOverlayBits->pitch;
1204 return S_OK;
1205}
1206
1207/**
1208 * Returns the current overlay height in pixels.
1209 *
1210 * @returns COM status code
1211 * @param height Address of result buffer.
1212 */
1213STDMETHODIMP VBoxSDLFBOverlay::COMGETTER(Height)(ULONG *height)
1214{
1215 LogFlow(("VBoxSDLFBOverlay::GetHeight\n"));
1216 if (!height)
1217 return E_INVALIDARG;
1218 *height = mOverlayHeight;
1219 return S_OK;
1220}
1221
1222/**
1223 * Returns whether the overlay is currently visible.
1224 *
1225 * @returns COM status code
1226 * @param visible Address of result buffer.
1227 */
1228STDMETHODIMP VBoxSDLFBOverlay::COMGETTER(Visible)(BOOL *visible)
1229{
1230 LogFlow(("VBoxSDLFBOverlay::GetVisible\n"));
1231 if (!visible)
1232 return E_INVALIDARG;
1233 *visible = mOverlayVisible;
1234 return S_OK;
1235}
1236
1237/**
1238 * Sets whether the overlay is currently visible.
1239 *
1240 * @returns COM status code
1241 * @param visible New value.
1242 */
1243STDMETHODIMP VBoxSDLFBOverlay::COMSETTER(Visible)(BOOL visible)
1244{
1245 LogFlow(("VBoxSDLFBOverlay::SetVisible\n"));
1246 mOverlayVisible = visible;
1247 return S_OK;
1248}
1249
1250/**
1251 * Returns the value of the global alpha channel.
1252 *
1253 * @returns COM status code
1254 * @param alpha Address of result buffer.
1255 */
1256STDMETHODIMP VBoxSDLFBOverlay::COMGETTER(Alpha)(ULONG *alpha)
1257{
1258 LogFlow(("VBoxSDLFBOverlay::GetAlpha\n"));
1259 return E_NOTIMPL;
1260}
1261
1262/**
1263 * Sets whether the overlay is currently visible.
1264 *
1265 * @returns COM status code
1266 * @param alpha new value.
1267 */
1268STDMETHODIMP VBoxSDLFBOverlay::COMSETTER(Alpha)(ULONG alpha)
1269{
1270 LogFlow(("VBoxSDLFBOverlay::SetAlpha\n"));
1271 return E_NOTIMPL;
1272}
1273
1274/**
1275 * Returns the address of the framebuffer bits for writing to.
1276 *
1277 * @returns COM status code
1278 * @param alpha Address of result buffer.
1279 */
1280STDMETHODIMP VBoxSDLFBOverlay::COMGETTER(Address)(ULONG *address)
1281{
1282 LogFlow(("VBoxSDLFBOverlay::GetAddress\n"));
1283 if (!address)
1284 return E_INVALIDARG;
1285 *address = (uintptr_t) mOverlayBits->pixels;
1286 return S_OK;
1287}
1288
1289/**
1290 * Returns the current colour depth. In fact, this is always 32bpp.
1291 *
1292 * @returns COM status code
1293 * @param bitsPerPixel Address of result buffer.
1294 */
1295STDMETHODIMP VBoxSDLFBOverlay::COMGETTER(BitsPerPixel)(ULONG *bitsPerPixel)
1296{
1297 LogFlow(("VBoxSDLFBOverlay::GetBitsPerPixel\n"));
1298 if (!bitsPerPixel)
1299 return E_INVALIDARG;
1300 *bitsPerPixel = 32;
1301 return S_OK;
1302}
1303
1304/**
1305 * Returns the current pixel format. In fact, this is always RGB.
1306 *
1307 * @returns COM status code
1308 * @param pixelFormat Address of result buffer.
1309 */
1310STDMETHODIMP VBoxSDLFBOverlay::COMGETTER(PixelFormat)(ULONG *pixelFormat)
1311{
1312 LogFlow(("VBoxSDLFBOverlay::GetPixelFormat\n"));
1313 if (!pixelFormat)
1314 return E_INVALIDARG;
1315 *pixelFormat = FramebufferPixelFormat_FOURCC_RGB;
1316 return S_OK;
1317}
1318
1319/**
1320 * Returns whether the guest VRAM is used directly. In fact, this is always FALSE.
1321 *
1322 * @returns COM status code
1323 * @param usesGuestVRAM Address of result buffer.
1324 */
1325STDMETHODIMP VBoxSDLFBOverlay::COMGETTER(UsesGuestVRAM)(BOOL *usesGuestVRAM)
1326{
1327 LogFlow(("VBoxSDLFBOverlay::GetUsesGuestVRAM\n"));
1328 if (!usesGuestVRAM)
1329 return E_INVALIDARG;
1330 *usesGuestVRAM = FALSE;
1331 return S_OK;
1332}
1333
1334/**
1335 * Returns the height reduction. In fact, this is always 0.
1336 *
1337 * @returns COM status code
1338 * @param heightReduction Address of result buffer.
1339 */
1340STDMETHODIMP VBoxSDLFBOverlay::COMGETTER(HeightReduction)(ULONG *heightReduction)
1341{
1342 LogFlow(("VBoxSDLFBOverlay::GetHeightReduction\n"));
1343 if (!heightReduction)
1344 return E_INVALIDARG;
1345 *heightReduction = 0;
1346 return S_OK;
1347}
1348
1349/**
1350 * Returns the overlay for this framebuffer. Obviously, we return NULL here.
1351 *
1352 * @returns COM status code
1353 * @param overlay Address of result buffer.
1354 */
1355STDMETHODIMP VBoxSDLFBOverlay::COMGETTER(Overlay)(IFramebufferOverlay **aOverlay)
1356{
1357 LogFlow(("VBoxSDLFBOverlay::GetOverlay\n"));
1358 if (!aOverlay)
1359 return E_INVALIDARG;
1360 *aOverlay = 0;
1361 return S_OK;
1362}
1363
1364/**
1365 * Lock the overlay. This should not be used - lock the parent IFramebuffer instead.
1366 *
1367 * @returns COM status code
1368 */
1369STDMETHODIMP VBoxSDLFBOverlay::Lock()
1370{
1371 LogFlow(("VBoxSDLFBOverlay::Lock\n"));
1372 AssertMsgFailed(("You should not attempt to lock an IFramebufferOverlay object -\n"
1373 "lock the parent IFramebuffer object instead.\n"));
1374 return E_NOTIMPL;
1375}
1376
1377/**
1378 * Unlock the overlay.
1379 *
1380 * @returns COM status code
1381 */
1382STDMETHODIMP VBoxSDLFBOverlay::Unlock()
1383{
1384 LogFlow(("VBoxSDLFBOverlay::Unlock\n"));
1385 AssertMsgFailed(("You should not attempt to lock an IFramebufferOverlay object -\n"
1386 "lock the parent IFramebuffer object instead.\n"));
1387 return E_NOTIMPL;
1388}
1389
1390/**
1391 * Change the X and Y co-ordinates of the overlay area.
1392 *
1393 * @returns COM status code
1394 * @param x New X co-ordinate.
1395 * @param y New Y co-ordinate.
1396 */
1397STDMETHODIMP VBoxSDLFBOverlay::Move(ULONG x, ULONG y)
1398{
1399 mOverlayX = x;
1400 mOverlayY = y;
1401 return S_OK;
1402}
1403
1404/**
1405 * Notify the overlay that a section of the framebuffer has been redrawn.
1406 *
1407 * @returns COM status code
1408 * @param x X co-ordinate of upper left corner of modified area.
1409 * @param y Y co-ordinate of upper left corner of modified area.
1410 * @param w Width of modified area.
1411 * @param h Height of modified area.
1412 * @retval finished Set if the operation has completed.
1413 *
1414 * All we do here is to send a request to the parent to update the affected area,
1415 * translating between our co-ordinate system and the parent's. It would be have
1416 * been better to call the parent directly, but such is life. We leave bounds
1417 * checking to the parent.
1418 */
1419STDMETHODIMP VBoxSDLFBOverlay::NotifyUpdate(ULONG x, ULONG y,
1420 ULONG w, ULONG h, BOOL *finished)
1421{
1422 return mParent->NotifyUpdate(x + mOverlayX, y + mOverlayY, w, h, finished);
1423}
1424
1425/**
1426 * Change the dimensions of the overlay.
1427 *
1428 * @returns COM status code
1429 * @param pixelFormat Must be FramebufferPixelFormat_PixelFormatRGB32.
1430 * @param vram Must be NULL.
1431 * @param lineSize Ignored.
1432 * @param w New overlay width.
1433 * @param h New overlay height.
1434 * @retval finished Set if the operation has completed.
1435 */
1436STDMETHODIMP VBoxSDLFBOverlay::RequestResize(ULONG aScreenId, ULONG pixelFormat, ULONG vram,
1437 ULONG bitsPerPixel, ULONG bytesPerLine,
1438 ULONG w, ULONG h, BOOL *finished)
1439{
1440 AssertReturn(pixelFormat == FramebufferPixelFormat_FOURCC_RGB, E_INVALIDARG);
1441 AssertReturn(vram == 0, E_INVALIDARG);
1442 AssertReturn(bitsPerPixel == 32, E_INVALIDARG);
1443 mOverlayWidth = w;
1444 mOverlayHeight = h;
1445 SDL_FreeSurface(mOverlayBits);
1446 mBlendedBits = SDL_CreateRGBSurface(SDL_ANYFORMAT, mOverlayWidth, mOverlayHeight, 32,
1447 0x00ff0000, 0x0000ff00, 0x000000ff, 0);
1448 AssertMsgReturn(mBlendedBits != NULL, ("Failed to create an SDL surface\n"),
1449 E_OUTOFMEMORY);
1450 mOverlayBits = SDL_CreateRGBSurface(SDL_SWSURFACE | SDL_SRCALPHA, mOverlayWidth,
1451 mOverlayHeight, 32, 0x00ff0000, 0x0000ff00,
1452 0x000000ff, 0xff000000);
1453 AssertMsgReturn(mOverlayBits != NULL, ("Failed to create an SDL surface\n"),
1454 E_OUTOFMEMORY);
1455 return S_OK;
1456}
1457
1458/**
1459 * Queries whether we support a given accelerated opperation. Since we do not currently
1460 * support any accelerated operations, we always return false in supported.
1461 *
1462 * @returns COM status code
1463 * @param operation The operation being queried
1464 * @retval supported Whether or not we support that operation
1465 */
1466STDMETHODIMP VBoxSDLFBOverlay::OperationSupported(FramebufferAccelerationOperation_T
1467 operation, BOOL *supported)
1468{
1469 if (!supported)
1470 return E_POINTER;
1471 /* We currently do not support any acceleration here, and will probably not in
1472 the forseeable future. */
1473 *supported = false;
1474 return S_OK;
1475}
1476
1477/**
1478 * Returns whether we like the given video mode.
1479 *
1480 * @returns COM status code
1481 * @param width video mode width in pixels
1482 * @param height video mode height in pixels
1483 * @param bpp video mode bit depth in bits per pixel
1484 * @retval supported pointer to result variable
1485 *
1486 * Basically, we support anything with 32bpp.
1487 */
1488STDMETHODIMP VBoxSDLFBOverlay::VideoModeSupported(ULONG width, ULONG height, ULONG bpp,
1489 BOOL *supported)
1490{
1491 if (!supported)
1492 return E_POINTER;
1493 if (bpp == 32)
1494 *supported = true;
1495 else
1496 *supported = false;
1497 return S_OK;
1498}
1499
1500/**
1501 * Fill an area of the framebuffer with solid colour
1502 *
1503 * @returns COM status code
1504 * @param x X co-ordinate of the area to fill, top-left corner
1505 * @param y Y co-ordinate of the area to fill, top-left corner
1506 * @param width width of the area to fill
1507 * @param height height of the area to fill
1508 * @param color colour with which to fill the area
1509 * @retval handled whether we support this operation or not
1510 *
1511 * Since we currently do not have any way of doing this faster than
1512 * the VGA device, we simply false in handled.
1513 */
1514STDMETHODIMP VBoxSDLFBOverlay::SolidFill(ULONG x, ULONG y, ULONG width,
1515 ULONG height, ULONG color, BOOL *handled)
1516{
1517 LogFlow(("VBoxSDLFBOverlay::SolidFill called\n"));
1518 if (!handled)
1519 return E_POINTER;
1520 *handled = false;
1521 return S_OK;
1522}
1523
1524/**
1525 * Since we currently do not have any way of doing this faster than
1526 * the VGA device, we simply false in handled.
1527 */
1528STDMETHODIMP VBoxSDLFBOverlay::CopyScreenBits(ULONG xDst, ULONG yDst, ULONG xSrc,
1529 ULONG ySrc, ULONG width,
1530 ULONG height, BOOL *handled)
1531{
1532 LogFlow(("VBoxSDLFBOverlay::CopyScreenBits called.\n"));
1533 if (!handled)
1534 return E_POINTER;
1535 *handled = false;
1536 return S_OK;
1537}
1538
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