VirtualBox

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

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

The Giant CDDL Dual-License Header Change.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 14.8 KB
Line 
1/** @file
2 *
3 * VBox frontends: Basic Frontend (BFE):
4 * Implementation of SDLFramebuffer 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#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, BOOL *finished)
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 /*
257 * The Display thread can continue as we will lock the framebuffer
258 * from the SDL thread when we get to actually doing the update.
259 */
260 if (finished)
261 *finished = TRUE;
262 return S_OK;
263}
264
265/**
266 * Request a display resize from the framebuffer.
267 *
268 * @returns COM status code.
269 * @param w New display width in pixels.
270 * @param h New display height in pixels.
271 * @param finished Address of output flag whether the update
272 * could be fully processed in this call (which
273 * has to return immediately) or VBox should wait
274 * for all call to the resize complete API before
275 * continuing with display updates.
276 */
277HRESULT SDLFramebuffer::RequestResize(ULONG w, ULONG h, BOOL *finished)
278{
279 LogFlow(("SDLFramebuffer::RequestResize: w = %d, h = %d\n", w, h));
280
281 /*
282 * SDL does not allow us to make this call from any other
283 * thread. So we have to send an event to the main SDL
284 * thread and tell VBox to wait.
285 */
286 if (!finished)
287 {
288 AssertMsgFailed(("RequestResize requires the finished flag!\n"));
289 return E_FAIL;
290 }
291 mWidth = w;
292 mHeight = h;
293
294 SDL_Event event;
295 event.type = SDL_USEREVENT;
296 event.user.type = SDL_USER_EVENT_RESIZE;
297
298 int rc = SDL_PushEvent(&event);
299 NOREF(rc);
300 AssertMsg(!rc, ("Error: SDL_PushEvent was not successful!\n"));
301
302 /* we want this request to be processed quickly, so yield the CPU */
303 RTThreadYield();
304
305 *finished = false;
306
307 return S_OK;
308}
309
310HRESULT SDLFramebuffer::SolidFill(ULONG x, ULONG y, ULONG width, ULONG height,
311 ULONG color, BOOL *handled)
312{
313 return E_NOTIMPL;
314}
315
316HRESULT SDLFramebuffer::CopyScreenBits(ULONG xDst, ULONG yDst, ULONG xSrc, ULONG ySrc,
317 ULONG width, ULONG height, BOOL *handled)
318{
319 return E_NOTIMPL;
320}
321
322HRESULT SDLFramebuffer::GetVisibleRegion(BYTE *aRectangles, ULONG aCount,
323 ULONG *aCountCopied)
324{
325 PRTRECT rects = (PRTRECT)aRectangles;
326
327 if (!rects)
328 return E_POINTER;
329
330 /// @todo
331
332 NOREF(aCount);
333 NOREF(aCountCopied);
334
335 return S_OK;
336}
337
338HRESULT SDLFramebuffer::SetVisibleRegion(BYTE *aRectangles, ULONG aCount)
339{
340 PRTRECT rects = (PRTRECT)aRectangles;
341
342 if (!rects)
343 return E_POINTER;
344
345 /// @todo
346
347 NOREF(aCount);
348
349 return S_OK;
350}
351
352//
353// Internal public methods
354//
355
356/**
357 * Method that does the actual resize.
358 *
359 * @remarks Must be called from the SDL thread!
360 */
361void SDLFramebuffer::resize()
362{
363 LogFlow(("VBoxSDL::resize() mWidth: %d, mHeight: %d\n", mWidth, mHeight));
364 AssertMsg(mSdlNativeThread == RTThreadNativeSelf(), ("Wrong thread! SDL is not threadsafe!\n"));
365
366 uint32_t newHeight = mHeight;
367 int sdlFlags = SDL_HWSURFACE | SDL_ASYNCBLIT | SDL_HWACCEL;
368 if (mfFullscreen)
369 {
370 sdlFlags |= SDL_FULLSCREEN;
371#ifdef RT_OS_WINDOWS
372 /* this flag causes a crash on Windows, mScreen->pixels is NULL */
373 sdlFlags &= ~SDL_HWSURFACE;
374 sdlFlags |= SDL_SWSURFACE;
375#endif
376 }
377
378#ifdef VBOX_SECURELABEL
379 /* try to add the label size */
380 newHeight = mHeight + mLabelHeight;
381#endif
382
383 mScreen = SDL_SetVideoMode(mWidth, newHeight, 0, sdlFlags);
384#ifdef VBOX_SECURELABEL
385 /* if it didn't work, then we have to go for the original resolution and paint over the guest */
386 if (!mScreen)
387 {
388 mScreen = SDL_SetVideoMode(mWidth, mHeight, 0, sdlFlags);
389 /* we don't have any extra space */
390 mTopOffset = 0;
391 }
392 else
393 {
394 /* we now have some extra space */
395 mTopOffset = mLabelHeight;
396 }
397#endif
398
399 AssertMsg(mScreen, ("Error: SDL_SetVideoMode failed!\n"));
400 if (mScreen)
401 AssertMsg(mScreen->pixels, ("Error: SDL_SetVideoMode returned NULL framebuffer!\n"));
402 repaint();
403}
404
405/**
406 * Update specified framebuffer area.
407 *
408 * @remarks Must be called from the SDL thread on Linux! Update region
409 * on the whole framebuffer, including y offset!
410 * @param x left column
411 * @param y top row
412 * @param w width in pixels
413 * @param h heigh in pixels
414 */
415void SDLFramebuffer::update(int x, int y, int w, int h)
416{
417#ifdef VBOXBFE_WITH_X11
418 AssertMsg(mSdlNativeThread == RTThreadNativeSelf(), ("Wrong thread! SDL is not threadsafe!\n"));
419#endif
420
421 Assert(mScreen);
422
423 uint32_t safeY = y;
424 uint32_t safeH = h;
425
426#ifdef VBOX_SECURELABEL
427 /*
428 * Cut down the update area to the untrusted portion
429 */
430 if (safeY < mLabelHeight)
431 safeY = mLabelHeight;
432 if ((safeH + mLabelHeight) > (mHeight + mTopOffset))
433 safeH = mHeight + mTopOffset - mLabelHeight;
434#endif
435
436 SDL_UpdateRect(mScreen, x, safeY, w, safeH);
437
438#ifdef VBOX_SECURELABEL
439 paintSecureLabel(x, y, w, h, false);
440#endif
441}
442
443/**
444 * Repaint the whole framebuffer
445 *
446 * @remarks Must be called from the SDL thread!
447 */
448void SDLFramebuffer::repaint()
449{
450 AssertMsg(mSdlNativeThread == RTThreadNativeSelf(), ("Wrong thread! SDL is not threadsafe!\n"));
451 LogFlow(("SDLFramebuffer::repaint\n"));
452 update(0, 0, mWidth, mHeight);
453}
454
455bool SDLFramebuffer::getFullscreen()
456{
457 LogFlow(("SDLFramebuffer::getFullscreen\n"));
458 return mfFullscreen;
459}
460
461/**
462 * Toggle fullscreen mode
463 *
464 * @remarks Must be called from the SDL thread!
465 */
466void SDLFramebuffer::setFullscreen(bool fFullscreen)
467{
468 AssertMsg(mSdlNativeThread == RTThreadNativeSelf(), ("Wrong thread! SDL is not threadsafe!\n"));
469 LogFlow(("SDLFramebuffer::SetFullscreen: fullscreen: %d\n", fFullscreen));
470 mfFullscreen = fFullscreen;
471 resize();
472}
473
474/**
475 * Returns the current y offset of the start of the guest screen
476 *
477 * @returns current y offset in pixels
478 */
479int SDLFramebuffer::getYOffset()
480{
481 return mTopOffset;
482}
483
484/**
485 * Returns the number of horizontal pixels of the host console
486 *
487 * @return X resolution
488 * @remarks currently not used in SDL mode
489 */
490int SDLFramebuffer::getHostXres()
491{
492 return 0;
493}
494
495/**
496 * Returns the number of vertical pixels of the host console
497 *
498 * @return Y resolution
499 * @remarks currently not used in SDL mode
500 */
501int SDLFramebuffer::getHostYres()
502{
503 return 0;
504}
505
506/**
507 * Returns the number of bits per pixels of the host console
508 *
509 * @return bits per pixel
510 * @remarks currently not used in SDL mode
511 */
512int SDLFramebuffer::getHostBitsPerPixel()
513{
514 return 0;
515}
516
517
518#ifdef VBOX_SECURELABEL
519/**
520 * Setup the secure labeling parameters
521 *
522 * @returns VBox status code
523 * @param height height of the secure label area in pixels
524 * @param font file path fo the TrueType font file
525 * @param pointsize font size in points
526 */
527int SDLFramebuffer::initSecureLabel(uint32_t height, char *font, uint32_t pointsize)
528{
529 LogFlow(("SDLFramebuffer:initSecureLabel: new offset: %d pixels, new font: %s, new pointsize: %d\n",
530 height, font, pointsize));
531 mLabelHeight = height;
532 Assert(font);
533 TTF_Init();
534 mLabelFont = TTF_OpenFont(font, pointsize);
535 if (!mLabelFont)
536 {
537 AssertMsgFailed(("Failed to open TTF font file %s\n", font));
538 return VERR_OPEN_FAILED;
539 }
540 repaint();
541 return VINF_SUCCESS;
542}
543
544/**
545 * Set the secure label text and repaint the label
546 *
547 * @param text UTF-8 string of new label
548 * @remarks must be called from the SDL thread!
549 */
550void SDLFramebuffer::setSecureLabelText(const char *text)
551{
552 mSecureLabelText = text;
553 paintSecureLabel(0, 0, 0, 0, true);
554}
555
556/**
557 * Paint the secure label if required
558 *
559 * @param fForce Force the repaint
560 * @remarks must be called from the SDL thread!
561 */
562void SDLFramebuffer::paintSecureLabel(int x, int y, int w, int h, bool fForce)
563{
564 AssertMsg(mSdlNativeThread == RTThreadNativeSelf(), ("Wrong thread! SDL is not threadsafe!\n"));
565 /* check if we can skip the paint */
566 if (!fForce && ((uint32_t)y > mLabelHeight))
567 {
568 return;
569 }
570 /* first fill the background */
571 SDL_Rect rect = {0, 0, mWidth, mLabelHeight};
572 SDL_FillRect(mScreen, &rect, SDL_MapRGB(mScreen->format, 255, 255, 0));
573 /* now the text */
574 if (mLabelFont && mSecureLabelText)
575 {
576 SDL_Color clrFg = {0, 0, 255, 0};
577 SDL_Surface *sText = TTF_RenderUTF8_Solid(mLabelFont, mSecureLabelText, clrFg);
578 rect.x = 10;
579 SDL_BlitSurface(sText, NULL, mScreen, &rect);
580 SDL_FreeSurface(sText);
581 }
582 /* make sure to update the screen */
583 SDL_UpdateRect(mScreen, 0, 0, mWidth, mLabelHeight);
584}
585#endif /* VBOX_SECURELABEL */
586
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