VirtualBox

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

Last change on this file since 8154 was 8154, checked in by vboxsync, 17 years ago

FE/SDL: introduced -seclabelofs

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette