VirtualBox

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

Last change on this file since 1 was 1, checked in by vboxsync, 55 years ago

import

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