VirtualBox

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

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

replace underscore symbols in VBoxBFE/ and VBoxSDL/

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

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