VirtualBox

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

Last change on this file since 20484 was 20433, checked in by vboxsync, 16 years ago

VBoxSDL: made it compile with SDL1.3 to support multiple guest monitors (disabled)

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