VirtualBox

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

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

The Big Sun Rebranding Header Change

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 14.9 KB
Line 
1/** @file
2 *
3 * VBox frontends: Basic Frontend (BFE):
4 * Implementation of SDLFramebuffer class
5 */
6
7/*
8 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
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 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
19 * Clara, CA 95054 USA or visit http://www.sun.com if you need
20 * additional information or have any questions.
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 (RT_OS_WINDOWS)
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 RT_OS_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(uintptr_t *address)
165{
166 LogFlow(("SDLFramebuffer::GetAddress\n"));
167 if (!address)
168 return E_INVALIDARG;
169
170 /* subtract the reserved extra area */
171 *address = mScreen
172 ? (uintptr_t)mScreen->pixels
173#ifdef RT_OS_OS2 /* Play safe for now - this is vital when we get a larger surface than requested. */
174 + mScreen->offset
175#endif
176 + (mScreen->pitch * mTopOffset)
177 : 0;
178
179 LogFlow(("VBoxSDL::GetAddress returning %p\n", *address));
180 return S_OK;
181}
182
183/**
184 * Return the current framebuffer color depth.
185 *
186 * @returns COM status code
187 * @param bitsPerPixel Address of result variable
188 */
189HRESULT SDLFramebuffer::getBitsPerPixel(ULONG *bitsPerPixel)
190{
191 LogFlow(("SDLFramebuffer::GetBitsPerPixel\n"));
192
193 if (!bitsPerPixel)
194 return E_INVALIDARG;
195 *bitsPerPixel = (ULONG)(mScreen ? mScreen->format->BitsPerPixel : 0);
196 return S_OK;
197}
198
199/**
200 * Return the current framebuffer line size in bytes.
201 *
202 * @returns COM status code.
203 * @param lineSize Address of result variable.
204 */
205HRESULT SDLFramebuffer::getLineSize(ULONG *lineSize)
206{
207 LogFlow(("SDLFramebuffer::GetLineSize\n"));
208 if (!lineSize)
209 return E_INVALIDARG;
210 *lineSize = (ULONG)(mScreen ? mScreen->pitch : 0);
211
212 return S_OK;
213}
214
215/**
216 * Notify framebuffer of an update.
217 *
218 * @returns COM status code
219 * @param x Update region upper left corner x value.
220 * @param y Update region upper left corner y value.
221 * @param w Update region width in pixels.
222 * @param h Update region height in pixels.
223 * @param finished Address of output flag whether the update
224 * could be fully processed in this call (which
225 * has to return immediately) or VBox should wait
226 * for a call to the update complete API before
227 * continuing with display updates.
228 */
229HRESULT SDLFramebuffer::NotifyUpdate(ULONG x, ULONG y,
230 ULONG w, ULONG h, BOOL *finished)
231{
232 LogFlow(("SDLFramebuffer::NotifyUpdate: x = %d, y = %d, w = %d, h = %d\n",
233 x, y, w, h));
234
235#ifdef VBOXBFE_WITH_X11
236 /*
237 * SDL does not allow us to make this call from any other
238 * thread. So we have to send an event to the main SDL
239 * thread and process it there. For sake of simplicity, we encode
240 * all information in the event parameters.
241 */
242 SDL_Event event;
243 event.type = SDL_USEREVENT;
244 event.user.type = SDL_USER_EVENT_UPDATERECT;
245 // 16 bit is enough for coordinates
246 event.user.data1 = (void*)(x << 16 | (y + mTopOffset));
247 event.user.data2 = (void*)(w << 16 | h);
248
249 int rc = SDL_PushEvent(&event);
250 // printf("%s:%d event=%p\n",__FILE__,__LINE__,&event);
251 NOREF(rc);
252 AssertMsg(!rc, ("Error: SDL_PushEvent was not successful! SDL error: '%s'\n",
253 SDL_GetError()));
254 /* in order to not flood the SDL event queue, yield the CPU */
255 RTThreadYield();
256#else /* !VBOXBFE_WITH_X11 */
257 update(x, y + mTopOffset, w, h);
258#endif /* !VBOXBFE_WITH_X11 */
259
260 /*
261 * The Display thread can continue as we will lock the framebuffer
262 * from the SDL thread when we get to actually doing the update.
263 */
264 if (finished)
265 *finished = TRUE;
266 return S_OK;
267}
268
269/**
270 * Request a display resize from the framebuffer.
271 *
272 * @returns COM status code.
273 * @param w New display width in pixels.
274 * @param h New display height in pixels.
275 * @param finished Address of output flag whether the update
276 * could be fully processed in this call (which
277 * has to return immediately) or VBox should wait
278 * for all call to the resize complete API before
279 * continuing with display updates.
280 */
281HRESULT SDLFramebuffer::RequestResize(ULONG w, ULONG h, BOOL *finished)
282{
283 LogFlow(("SDLFramebuffer::RequestResize: w = %d, h = %d\n", w, h));
284
285 /*
286 * SDL does not allow us to make this call from any other
287 * thread. So we have to send an event to the main SDL
288 * thread and tell VBox to wait.
289 */
290 if (!finished)
291 {
292 AssertMsgFailed(("RequestResize requires the finished flag!\n"));
293 return E_FAIL;
294 }
295 mWidth = w;
296 mHeight = h;
297
298 SDL_Event event;
299 event.type = SDL_USEREVENT;
300 event.user.type = SDL_USER_EVENT_RESIZE;
301
302 int rc = SDL_PushEvent(&event);
303 NOREF(rc);
304 AssertMsg(!rc, ("Error: SDL_PushEvent was not successful!\n"));
305
306 /* we want this request to be processed quickly, so yield the CPU */
307 RTThreadYield();
308
309 *finished = false;
310
311 return S_OK;
312}
313
314HRESULT SDLFramebuffer::SolidFill(ULONG x, ULONG y, ULONG width, ULONG height,
315 ULONG color, BOOL *handled)
316{
317 return E_NOTIMPL;
318}
319
320HRESULT SDLFramebuffer::CopyScreenBits(ULONG xDst, ULONG yDst, ULONG xSrc, ULONG ySrc,
321 ULONG width, ULONG height, BOOL *handled)
322{
323 return E_NOTIMPL;
324}
325
326HRESULT SDLFramebuffer::GetVisibleRegion(BYTE *aRectangles, ULONG aCount,
327 ULONG *aCountCopied)
328{
329 PRTRECT rects = (PRTRECT)aRectangles;
330
331 if (!rects)
332 return E_POINTER;
333
334 /// @todo
335
336 NOREF(aCount);
337 NOREF(aCountCopied);
338
339 return S_OK;
340}
341
342HRESULT SDLFramebuffer::SetVisibleRegion(BYTE *aRectangles, ULONG aCount)
343{
344 PRTRECT rects = (PRTRECT)aRectangles;
345
346 if (!rects)
347 return E_POINTER;
348
349 /// @todo
350
351 NOREF(aCount);
352
353 return S_OK;
354}
355
356//
357// Internal public methods
358//
359
360/**
361 * Method that does the actual resize.
362 *
363 * @remarks Must be called from the SDL thread!
364 */
365void SDLFramebuffer::resize()
366{
367 LogFlow(("VBoxSDL::resize() mWidth: %d, mHeight: %d\n", mWidth, mHeight));
368 AssertMsg(mSdlNativeThread == RTThreadNativeSelf(), ("Wrong thread! SDL is not threadsafe!\n"));
369
370 uint32_t newHeight = mHeight;
371 int sdlFlags = SDL_HWSURFACE | SDL_ASYNCBLIT | SDL_HWACCEL;
372 if (mfFullscreen)
373 {
374 sdlFlags |= SDL_FULLSCREEN;
375#ifdef RT_OS_WINDOWS
376 /* this flag causes a crash on Windows, mScreen->pixels is NULL */
377 sdlFlags &= ~SDL_HWSURFACE;
378 sdlFlags |= SDL_SWSURFACE;
379#endif
380 }
381
382#ifdef VBOX_SECURELABEL
383 /* try to add the label size */
384 newHeight = mHeight + mLabelHeight;
385#endif
386
387 mScreen = SDL_SetVideoMode(mWidth, newHeight, 0, sdlFlags);
388#ifdef VBOX_SECURELABEL
389 /* if it didn't work, then we have to go for the original resolution and paint over the guest */
390 if (!mScreen)
391 {
392 mScreen = SDL_SetVideoMode(mWidth, mHeight, 0, sdlFlags);
393 /* we don't have any extra space */
394 mTopOffset = 0;
395 }
396 else
397 {
398 /* we now have some extra space */
399 mTopOffset = mLabelHeight;
400 }
401#endif
402
403 AssertMsg(mScreen, ("Error: SDL_SetVideoMode failed!\n"));
404 if (mScreen)
405 AssertMsg(mScreen->pixels, ("Error: SDL_SetVideoMode returned NULL framebuffer!\n"));
406 repaint();
407}
408
409/**
410 * Update specified framebuffer area.
411 *
412 * @remarks Must be called from the SDL thread on Linux! Update region
413 * on the whole framebuffer, including y offset!
414 * @param x left column
415 * @param y top row
416 * @param w width in pixels
417 * @param h heigh in pixels
418 */
419void SDLFramebuffer::update(int x, int y, int w, int h)
420{
421#ifdef VBOXBFE_WITH_X11
422 AssertMsg(mSdlNativeThread == RTThreadNativeSelf(), ("Wrong thread! SDL is not threadsafe!\n"));
423#endif
424
425 Assert(mScreen);
426
427 uint32_t safeY = y;
428 uint32_t safeH = h;
429
430#ifdef VBOX_SECURELABEL
431 /*
432 * Cut down the update area to the untrusted portion
433 */
434 if (safeY < mLabelHeight)
435 safeY = mLabelHeight;
436 if ((safeH + mLabelHeight) > (mHeight + mTopOffset))
437 safeH = mHeight + mTopOffset - mLabelHeight;
438#endif
439
440 SDL_UpdateRect(mScreen, x, safeY, w, safeH);
441
442#ifdef VBOX_SECURELABEL
443 paintSecureLabel(x, y, w, h, false);
444#endif
445}
446
447/**
448 * Repaint the whole framebuffer
449 *
450 * @remarks Must be called from the SDL thread!
451 */
452void SDLFramebuffer::repaint()
453{
454 AssertMsg(mSdlNativeThread == RTThreadNativeSelf(), ("Wrong thread! SDL is not threadsafe!\n"));
455 LogFlow(("SDLFramebuffer::repaint\n"));
456 update(0, 0, mWidth, mHeight);
457}
458
459bool SDLFramebuffer::getFullscreen()
460{
461 LogFlow(("SDLFramebuffer::getFullscreen\n"));
462 return mfFullscreen;
463}
464
465/**
466 * Toggle fullscreen mode
467 *
468 * @remarks Must be called from the SDL thread!
469 */
470void SDLFramebuffer::setFullscreen(bool fFullscreen)
471{
472 AssertMsg(mSdlNativeThread == RTThreadNativeSelf(), ("Wrong thread! SDL is not threadsafe!\n"));
473 LogFlow(("SDLFramebuffer::SetFullscreen: fullscreen: %d\n", fFullscreen));
474 mfFullscreen = fFullscreen;
475 resize();
476}
477
478/**
479 * Returns the current y offset of the start of the guest screen
480 *
481 * @returns current y offset in pixels
482 */
483int SDLFramebuffer::getYOffset()
484{
485 return mTopOffset;
486}
487
488/**
489 * Returns the number of horizontal pixels of the host console
490 *
491 * @return X resolution
492 * @remarks currently not used in SDL mode
493 */
494int SDLFramebuffer::getHostXres()
495{
496 return 0;
497}
498
499/**
500 * Returns the number of vertical pixels of the host console
501 *
502 * @return Y resolution
503 * @remarks currently not used in SDL mode
504 */
505int SDLFramebuffer::getHostYres()
506{
507 return 0;
508}
509
510/**
511 * Returns the number of bits per pixels of the host console
512 *
513 * @return bits per pixel
514 * @remarks currently not used in SDL mode
515 */
516int SDLFramebuffer::getHostBitsPerPixel()
517{
518 return 0;
519}
520
521
522#ifdef VBOX_SECURELABEL
523/**
524 * Setup the secure labeling parameters
525 *
526 * @returns VBox status code
527 * @param height height of the secure label area in pixels
528 * @param font file path fo the TrueType font file
529 * @param pointsize font size in points
530 */
531int SDLFramebuffer::initSecureLabel(uint32_t height, char *font, uint32_t pointsize)
532{
533 LogFlow(("SDLFramebuffer:initSecureLabel: new offset: %d pixels, new font: %s, new pointsize: %d\n",
534 height, font, pointsize));
535 mLabelHeight = height;
536 Assert(font);
537 TTF_Init();
538 mLabelFont = TTF_OpenFont(font, pointsize);
539 if (!mLabelFont)
540 {
541 AssertMsgFailed(("Failed to open TTF font file %s\n", font));
542 return VERR_OPEN_FAILED;
543 }
544 repaint();
545 return VINF_SUCCESS;
546}
547
548/**
549 * Set the secure label text and repaint the label
550 *
551 * @param text UTF-8 string of new label
552 * @remarks must be called from the SDL thread!
553 */
554void SDLFramebuffer::setSecureLabelText(const char *text)
555{
556 mSecureLabelText = text;
557 paintSecureLabel(0, 0, 0, 0, true);
558}
559
560/**
561 * Paint the secure label if required
562 *
563 * @param fForce Force the repaint
564 * @remarks must be called from the SDL thread!
565 */
566void SDLFramebuffer::paintSecureLabel(int x, int y, int w, int h, bool fForce)
567{
568 AssertMsg(mSdlNativeThread == RTThreadNativeSelf(), ("Wrong thread! SDL is not threadsafe!\n"));
569 /* check if we can skip the paint */
570 if (!fForce && ((uint32_t)y > mLabelHeight))
571 {
572 return;
573 }
574 /* first fill the background */
575 SDL_Rect rect = {0, 0, mWidth, mLabelHeight};
576 SDL_FillRect(mScreen, &rect, SDL_MapRGB(mScreen->format, 255, 255, 0));
577 /* now the text */
578 if (mLabelFont && mSecureLabelText)
579 {
580 SDL_Color clrFg = {0, 0, 255, 0};
581 SDL_Surface *sText = TTF_RenderUTF8_Solid(mLabelFont, mSecureLabelText, clrFg);
582 rect.x = 10;
583 SDL_BlitSurface(sText, NULL, mScreen, &rect);
584 SDL_FreeSurface(sText);
585 }
586 /* make sure to update the screen */
587 SDL_UpdateRect(mScreen, 0, 0, mWidth, mLabelHeight);
588}
589#endif /* VBOX_SECURELABEL */
590
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