VirtualBox

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

Last change on this file since 62517 was 60759, checked in by vboxsync, 9 years ago

Frontends: various cleanups, mostly ATL related, remove code for no longer existing API method

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