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