VirtualBox

source: vbox/trunk/src/VBox/Frontends/VBoxBFE/SDLFramebuffer.cpp@ 41105

Last change on this file since 41105 was 33540, checked in by vboxsync, 14 years ago

*: spelling fixes, thanks Timeless!

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 14.3 KB
Line 
1/** @file
2 *
3 * VBox frontends: Basic Frontend (BFE):
4 * Implementation of SDLFramebuffer class
5 */
6
7/*
8 * Copyright (C) 2006-2007 Oracle Corporation
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 */
18
19#ifdef VBOXBFE_WITHOUT_COM
20# include "COMDefs.h"
21#else
22# include <VBox/com/com.h>
23# include <VBox/com/string.h>
24# include <VBox/com/Guid.h>
25#endif
26
27#define LOG_GROUP LOG_GROUP_GUI
28#include <VBox/err.h>
29#include <VBox/log.h>
30
31#include <signal.h>
32
33#include "SDLFramebuffer.h"
34
35//
36// Constructor / destructor
37//
38
39/**
40 * SDL framebuffer constructor. It is called from the main
41 * (i.e. SDL) thread. Therefore it is safe to use SDL calls
42 * here.
43 */
44SDLFramebuffer::SDLFramebuffer()
45{
46 int rc;
47 LogFlow(("SDLFramebuffer::SDLFramebuffer\n"));
48
49#if defined (RT_OS_WINDOWS)
50 refcnt = 0;
51#endif
52
53 mScreen = NULL;
54 mfFullscreen = false;
55 mTopOffset = 0;
56
57 /* memorize the thread that inited us, that's the SDL thread */
58 mSdlNativeThread = RTThreadNativeSelf();
59
60 rc = RTCritSectInit(&mUpdateLock);
61 AssertMsg(rc == VINF_SUCCESS, ("Error from RTCritSectInit!\n"));
62
63#ifdef VBOX_SECURELABEL
64 mLabelFont = NULL;
65 mLabelHeight = 0;
66#endif
67
68#ifdef RT_OS_LINUX
69 /* NOTE: we still want Ctrl-C to work, so we undo the SDL redirections */
70 signal(SIGINT, SIG_DFL);
71 signal(SIGQUIT, SIG_DFL);
72#endif
73
74 /*
75 * Start with standard screen dimensions.
76 */
77 mWidth = 640;
78 mHeight = 480;
79 resize();
80 Assert(mScreen);
81}
82
83SDLFramebuffer::~SDLFramebuffer()
84{
85 LogFlow(("SDLFramebuffer::~SDLFramebuffer\n"));
86 RTCritSectDelete(&mUpdateLock);
87
88 AssertMsg(mSdlNativeThread == RTThreadNativeSelf(), ("Wrong thread! SDL is not threadsafe!\n"));
89 SDL_QuitSubSystem(SDL_INIT_VIDEO);
90#ifdef VBOX_SECURELABEL
91 if (mLabelFont)
92 TTF_CloseFont(mLabelFont);
93 TTF_Quit();
94#endif
95 mScreen = NULL;
96
97}
98
99
100/**
101 * Returns the current framebuffer width in pixels.
102 *
103 * @returns COM status code
104 * @param width Address of result buffer.
105 */
106HRESULT SDLFramebuffer::getWidth(ULONG *width)
107{
108 LogFlow(("SDLFramebuffer::GetWidth\n"));
109 if (!width)
110 return E_INVALIDARG;
111 *width = mWidth;
112 return S_OK;
113}
114
115/**
116 * Returns the current framebuffer height in pixels.
117 *
118 * @returns COM status code
119 * @param height Address of result buffer.
120 */
121HRESULT SDLFramebuffer::getHeight(ULONG *height)
122{
123 LogFlow(("SDLFramebuffer::GetHeight\n"));
124 if (!height)
125 return E_INVALIDARG;
126 *height = mHeight;
127 return S_OK;
128}
129
130/**
131 * Lock the framebuffer (make its address immutable).
132 *
133 * @returns COM status code
134 */
135HRESULT SDLFramebuffer::Lock()
136{
137 LogFlow(("SDLFramebuffer::Lock\n"));
138 RTCritSectEnter(&mUpdateLock);
139 return S_OK;
140}
141
142/**
143 * Unlock the framebuffer.
144 *
145 * @returns COM status code
146 */
147HRESULT SDLFramebuffer::Unlock()
148{
149 LogFlow(("SDLFramebuffer::Unlock\n"));
150 RTCritSectLeave(&mUpdateLock);
151 return S_OK;
152}
153
154/**
155 * Return the framebuffer start address.
156 *
157 * @returns COM status code.
158 * @param address Pointer to result variable.
159 */
160HRESULT SDLFramebuffer::getAddress(uintptr_t *address)
161{
162 LogFlow(("SDLFramebuffer::GetAddress\n"));
163 if (!address)
164 return E_INVALIDARG;
165
166 /* subtract the reserved extra area */
167 *address = mScreen
168 ? (uintptr_t)mScreen->pixels
169#ifdef RT_OS_OS2 /* Play safe for now - this is vital when we get a larger surface than requested. */
170 + mScreen->offset
171#endif
172 + (mScreen->pitch * mTopOffset)
173 : 0;
174
175 LogFlow(("VBoxSDL::GetAddress returning %p\n", *address));
176 return S_OK;
177}
178
179/**
180 * Return the current framebuffer color depth.
181 *
182 * @returns COM status code
183 * @param bitsPerPixel Address of result variable
184 */
185HRESULT SDLFramebuffer::getBitsPerPixel(ULONG *bitsPerPixel)
186{
187 LogFlow(("SDLFramebuffer::GetBitsPerPixel\n"));
188
189 if (!bitsPerPixel)
190 return E_INVALIDARG;
191 *bitsPerPixel = (ULONG)(mScreen ? mScreen->format->BitsPerPixel : 0);
192 return S_OK;
193}
194
195/**
196 * Return the current framebuffer line size in bytes.
197 *
198 * @returns COM status code.
199 * @param lineSize Address of result variable.
200 */
201HRESULT SDLFramebuffer::getLineSize(ULONG *lineSize)
202{
203 LogFlow(("SDLFramebuffer::GetLineSize\n"));
204 if (!lineSize)
205 return E_INVALIDARG;
206 *lineSize = (ULONG)(mScreen ? mScreen->pitch : 0);
207
208 return S_OK;
209}
210
211/**
212 * Notify framebuffer of an update.
213 *
214 * @returns COM status code
215 * @param x Update region upper left corner x value.
216 * @param y Update region upper left corner y value.
217 * @param w Update region width in pixels.
218 * @param h Update region height in pixels.
219 * @param finished Address of output flag whether the update
220 * could be fully processed in this call (which
221 * has to return immediately) or VBox should wait
222 * for a call to the update complete API before
223 * continuing with display updates.
224 */
225HRESULT SDLFramebuffer::NotifyUpdate(ULONG x, ULONG y,
226 ULONG w, ULONG h)
227{
228 LogFlow(("SDLFramebuffer::NotifyUpdate: x = %d, y = %d, w = %d, h = %d\n",
229 x, y, w, h));
230
231#ifdef VBOXBFE_WITH_X11
232 /*
233 * SDL does not allow us to make this call from any other
234 * thread. So we have to send an event to the main SDL
235 * thread and process it there. For sake of simplicity, we encode
236 * all information in the event parameters.
237 */
238 SDL_Event event;
239 event.type = SDL_USEREVENT;
240 event.user.type = SDL_USER_EVENT_UPDATERECT;
241 // 16 bit is enough for coordinates
242 event.user.data1 = (void*)(x << 16 | (y + mTopOffset));
243 event.user.data2 = (void*)(w << 16 | h);
244
245 int rc = SDL_PushEvent(&event);
246 // printf("%s:%d event=%p\n",__FILE__,__LINE__,&event);
247 NOREF(rc);
248 AssertMsg(!rc, ("Error: SDL_PushEvent was not successful! SDL error: '%s'\n",
249 SDL_GetError()));
250 /* in order to not flood the SDL event queue, yield the CPU */
251 RTThreadYield();
252#else /* !VBOXBFE_WITH_X11 */
253 update(x, y + mTopOffset, w, h);
254#endif /* !VBOXBFE_WITH_X11 */
255
256 return S_OK;
257}
258
259/**
260 * Request a display resize from the framebuffer.
261 *
262 * @returns COM status code.
263 * @param w New display width in pixels.
264 * @param h New display height in pixels.
265 * @param finished Address of output flag whether the update
266 * could be fully processed in this call (which
267 * has to return immediately) or VBox should wait
268 * for all call to the resize complete API before
269 * continuing with display updates.
270 */
271HRESULT SDLFramebuffer::RequestResize(ULONG w, ULONG h, BOOL *finished)
272{
273 LogFlow(("SDLFramebuffer::RequestResize: w = %d, h = %d\n", w, h));
274
275 /*
276 * SDL does not allow us to make this call from any other
277 * thread. So we have to send an event to the main SDL
278 * thread and tell VBox to wait.
279 */
280 if (!finished)
281 {
282 AssertMsgFailed(("RequestResize requires the finished flag!\n"));
283 return E_FAIL;
284 }
285 mWidth = w;
286 mHeight = h;
287
288 SDL_Event event;
289 event.type = SDL_USEREVENT;
290 event.user.type = SDL_USER_EVENT_RESIZE;
291
292 int rc = SDL_PushEvent(&event);
293 NOREF(rc);
294 AssertMsg(!rc, ("Error: SDL_PushEvent was not successful!\n"));
295
296 /* we want this request to be processed quickly, so yield the CPU */
297 RTThreadYield();
298
299 *finished = false;
300
301 return S_OK;
302}
303
304HRESULT SDLFramebuffer::GetVisibleRegion(BYTE *aRectangles, ULONG aCount,
305 ULONG *aCountCopied)
306{
307 PRTRECT rects = (PRTRECT)aRectangles;
308
309 if (!rects)
310 return E_POINTER;
311
312 /// @todo
313
314 NOREF(aCount);
315 NOREF(aCountCopied);
316
317 return S_OK;
318}
319
320HRESULT SDLFramebuffer::SetVisibleRegion(BYTE *aRectangles, ULONG aCount)
321{
322 PRTRECT rects = (PRTRECT)aRectangles;
323
324 if (!rects)
325 return E_POINTER;
326
327 /// @todo
328
329 NOREF(aCount);
330
331 return S_OK;
332}
333
334HRESULT SDLFramebuffer::ProcessVHWACommand(BYTE *pCommand)
335{
336 return E_NOTIMPL;
337}
338
339//
340// Internal public methods
341//
342
343/**
344 * Method that does the actual resize.
345 *
346 * @remarks Must be called from the SDL thread!
347 */
348void SDLFramebuffer::resize()
349{
350 LogFlow(("VBoxSDL::resize() mWidth: %d, mHeight: %d\n", mWidth, mHeight));
351 AssertMsg(mSdlNativeThread == RTThreadNativeSelf(), ("Wrong thread! SDL is not threadsafe!\n"));
352
353 uint32_t newHeight = mHeight;
354 int sdlFlags = SDL_HWSURFACE | SDL_ASYNCBLIT | SDL_HWACCEL;
355 if (mfFullscreen)
356 {
357 sdlFlags |= SDL_FULLSCREEN;
358#ifdef RT_OS_WINDOWS
359 /* this flag causes a crash on Windows, mScreen->pixels is NULL */
360 sdlFlags &= ~SDL_HWSURFACE;
361 sdlFlags |= SDL_SWSURFACE;
362#endif
363 }
364
365#ifdef VBOX_SECURELABEL
366 /* try to add the label size */
367 newHeight = mHeight + mLabelHeight;
368#endif
369
370 mScreen = SDL_SetVideoMode(mWidth, newHeight, 0, sdlFlags);
371#ifdef VBOX_SECURELABEL
372 /* if it didn't work, then we have to go for the original resolution and paint over the guest */
373 if (!mScreen)
374 {
375 mScreen = SDL_SetVideoMode(mWidth, mHeight, 0, sdlFlags);
376 /* we don't have any extra space */
377 mTopOffset = 0;
378 }
379 else
380 {
381 /* we now have some extra space */
382 mTopOffset = mLabelHeight;
383 }
384#endif
385
386 AssertMsg(mScreen, ("Error: SDL_SetVideoMode failed!\n"));
387 if (mScreen)
388 AssertMsg(mScreen->pixels, ("Error: SDL_SetVideoMode returned NULL framebuffer!\n"));
389 repaint();
390}
391
392/**
393 * Update specified framebuffer area.
394 *
395 * @remarks Must be called from the SDL thread on Linux! Update region
396 * on the whole framebuffer, including y offset!
397 * @param x left column
398 * @param y top row
399 * @param w width in pixels
400 * @param h height in pixels
401 */
402void SDLFramebuffer::update(int x, int y, int w, int h)
403{
404#ifdef VBOXBFE_WITH_X11
405 AssertMsg(mSdlNativeThread == RTThreadNativeSelf(), ("Wrong thread! SDL is not threadsafe!\n"));
406#endif
407
408 Assert(mScreen);
409
410 uint32_t safeY = y;
411 uint32_t safeH = h;
412
413#ifdef VBOX_SECURELABEL
414 /*
415 * Cut down the update area to the untrusted portion
416 */
417 if (safeY < mLabelHeight)
418 safeY = mLabelHeight;
419 if ((safeH + mLabelHeight) > (mHeight + mTopOffset))
420 safeH = mHeight + mTopOffset - mLabelHeight;
421#endif
422
423 SDL_UpdateRect(mScreen, x, safeY, w, safeH);
424
425#ifdef VBOX_SECURELABEL
426 paintSecureLabel(x, y, w, h, false);
427#endif
428}
429
430/**
431 * Repaint the whole framebuffer
432 *
433 * @remarks Must be called from the SDL thread!
434 */
435void SDLFramebuffer::repaint()
436{
437 AssertMsg(mSdlNativeThread == RTThreadNativeSelf(), ("Wrong thread! SDL is not threadsafe!\n"));
438 LogFlow(("SDLFramebuffer::repaint\n"));
439 update(0, 0, mWidth, mHeight);
440}
441
442bool SDLFramebuffer::getFullscreen()
443{
444 LogFlow(("SDLFramebuffer::getFullscreen\n"));
445 return mfFullscreen;
446}
447
448/**
449 * Toggle fullscreen mode
450 *
451 * @remarks Must be called from the SDL thread!
452 */
453void SDLFramebuffer::setFullscreen(bool fFullscreen)
454{
455 AssertMsg(mSdlNativeThread == RTThreadNativeSelf(), ("Wrong thread! SDL is not threadsafe!\n"));
456 LogFlow(("SDLFramebuffer::SetFullscreen: fullscreen: %d\n", fFullscreen));
457 mfFullscreen = fFullscreen;
458 resize();
459}
460
461/**
462 * Returns the current y offset of the start of the guest screen
463 *
464 * @returns current y offset in pixels
465 */
466int SDLFramebuffer::getYOffset()
467{
468 return mTopOffset;
469}
470
471/**
472 * Returns the number of horizontal pixels of the host console
473 *
474 * @return X resolution
475 * @remarks currently not used in SDL mode
476 */
477int SDLFramebuffer::getHostXres()
478{
479 return 0;
480}
481
482/**
483 * Returns the number of vertical pixels of the host console
484 *
485 * @return Y resolution
486 * @remarks currently not used in SDL mode
487 */
488int SDLFramebuffer::getHostYres()
489{
490 return 0;
491}
492
493/**
494 * Returns the number of bits per pixels of the host console
495 *
496 * @return bits per pixel
497 * @remarks currently not used in SDL mode
498 */
499int SDLFramebuffer::getHostBitsPerPixel()
500{
501 return 0;
502}
503
504
505#ifdef VBOX_SECURELABEL
506/**
507 * Setup the secure labeling parameters
508 *
509 * @returns VBox status code
510 * @param height height of the secure label area in pixels
511 * @param font file path fo the TrueType font file
512 * @param pointsize font size in points
513 */
514int SDLFramebuffer::initSecureLabel(uint32_t height, char *font, uint32_t pointsize)
515{
516 LogFlow(("SDLFramebuffer:initSecureLabel: new offset: %d pixels, new font: %s, new pointsize: %d\n",
517 height, font, pointsize));
518 mLabelHeight = height;
519 Assert(font);
520 TTF_Init();
521 mLabelFont = TTF_OpenFont(font, pointsize);
522 if (!mLabelFont)
523 {
524 AssertMsgFailed(("Failed to open TTF font file %s\n", font));
525 return VERR_OPEN_FAILED;
526 }
527 repaint();
528 return VINF_SUCCESS;
529}
530
531/**
532 * Set the secure label text and repaint the label
533 *
534 * @param text UTF-8 string of new label
535 * @remarks must be called from the SDL thread!
536 */
537void SDLFramebuffer::setSecureLabelText(const char *text)
538{
539 mSecureLabelText = text;
540 paintSecureLabel(0, 0, 0, 0, true);
541}
542
543/**
544 * Paint the secure label if required
545 *
546 * @param fForce Force the repaint
547 * @remarks must be called from the SDL thread!
548 */
549void SDLFramebuffer::paintSecureLabel(int x, int y, int w, int h, bool fForce)
550{
551 AssertMsg(mSdlNativeThread == RTThreadNativeSelf(), ("Wrong thread! SDL is not threadsafe!\n"));
552 /* check if we can skip the paint */
553 if (!fForce && ((uint32_t)y > mLabelHeight))
554 {
555 return;
556 }
557 /* first fill the background */
558 SDL_Rect rect = {0, 0, mWidth, mLabelHeight};
559 SDL_FillRect(mScreen, &rect, SDL_MapRGB(mScreen->format, 255, 255, 0));
560 /* now the text */
561 if (mLabelFont && mSecureLabelText)
562 {
563 SDL_Color clrFg = {0, 0, 255, 0};
564 SDL_Surface *sText = TTF_RenderUTF8_Solid(mLabelFont, mSecureLabelText, clrFg);
565 rect.x = 10;
566 SDL_BlitSurface(sText, NULL, mScreen, &rect);
567 SDL_FreeSurface(sText);
568 }
569 /* make sure to update the screen */
570 SDL_UpdateRect(mScreen, 0, 0, mWidth, mLabelHeight);
571}
572#endif /* VBOX_SECURELABEL */
573
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