VirtualBox

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

Last change on this file since 51610 was 51610, checked in by vboxsync, 11 years ago

Reverted r94341: too early.

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