ResidualVM logo ResidualVM website - Forums - Contact us BuildBot - Doxygen - Wiki curved edge

sdl.cpp

Go to the documentation of this file.
00001 /* ScummVM - Graphic Adventure Engine
00002  *
00003  * ScummVM is the legal property of its developers, whose names
00004  * are too numerous to list here. Please refer to the COPYRIGHT
00005  * file distributed with this source distribution.
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 #define FORBIDDEN_SYMBOL_ALLOW_ALL
00024 
00025 #include "backends/platform/sdl/sdl.h"
00026 #include "common/config-manager.h"
00027 #include "gui/EventRecorder.h"
00028 #include "common/taskbar.h"
00029 #include "common/textconsole.h"
00030 #include "common/translation.h"
00031 
00032 #include "backends/saves/default/default-saves.h"
00033 
00034 // Audio CD support was removed with SDL 2.0
00035 #if SDL_VERSION_ATLEAST(2, 0, 0)
00036 #include "backends/audiocd/default/default-audiocd.h"
00037 #else
00038 #include "backends/audiocd/sdl/sdl-audiocd.h"
00039 #endif
00040 #include "backends/events/default/default-events.h"
00041 // ResidualVM:
00042 // #include "backends/events/sdl/sdl-events.h"
00043 #include "backends/events/sdl/resvm-sdl-events.h"
00044 #include "backends/mutex/sdl/sdl-mutex.h"
00045 #include "backends/timer/sdl/sdl-timer.h"
00046 #include "backends/graphics/surfacesdl/surfacesdl-graphics.h"
00047 
00048 #ifdef USE_OPENGL
00049 #include "backends/graphics/openglsdl/openglsdl-graphics.h"
00050 //#include "graphics/cursorman.h" // ResidualVM
00051 #include "graphics/opengl/context.h" // ResidualVM specific
00052 #endif
00053 #include "graphics/renderer.h" // ResidualVM specific
00054 
00055 #include <time.h>   // for getTimeAndDate()
00056 
00057 #ifdef USE_DETECTLANG
00058 #ifndef WIN32
00059 #include <locale.h>
00060 #endif // !WIN32
00061 #endif
00062 
00063 #ifdef USE_SDL_NET
00064 #include <SDL_net.h>
00065 #endif
00066 
00067 #if SDL_VERSION_ATLEAST(2, 0, 0)
00068 #include <SDL_clipboard.h>
00069 #endif
00070 
00071 OSystem_SDL::OSystem_SDL()
00072     :
00073     _inited(false),
00074     _initedSDL(false),
00075 #ifdef USE_SDL_NET
00076     _initedSDLnet(false),
00077 #endif
00078     _logger(0),
00079     _mixerManager(0),
00080     _eventSource(0),
00081     _window(0) {
00082 
00083     ConfMan.registerDefault("kbdmouse_speed", 3);
00084     ConfMan.registerDefault("joystick_deadzone", 3);
00085 }
00086 
00087 OSystem_SDL::~OSystem_SDL() {
00088     SDL_ShowCursor(SDL_ENABLE);
00089 
00090     // Delete the various managers here. Note that the ModularBackend
00091     // destructor would also take care of this for us. However, various
00092     // of our managers must be deleted *before* we call SDL_Quit().
00093     // Hence, we perform the destruction on our own.
00094     delete _savefileManager;
00095     _savefileManager = 0;
00096     if (_graphicsManager) {
00097         dynamic_cast<SdlGraphicsManager *>(_graphicsManager)->deactivateManager();
00098     }
00099     delete _graphicsManager;
00100     _graphicsManager = 0;
00101     delete _window;
00102     _window = 0;
00103     delete _eventManager;
00104     _eventManager = 0;
00105     delete _eventSource;
00106     _eventSource = 0;
00107     delete _audiocdManager;
00108     _audiocdManager = 0;
00109     delete _mixerManager;
00110     _mixerManager = 0;
00111 
00112 #ifdef ENABLE_EVENTRECORDER
00113     // HACK HACK HACK
00114     // This is nasty.
00115     delete g_eventRec.getTimerManager();
00116 #else
00117     delete _timerManager;
00118 #endif
00119 
00120     _timerManager = 0;
00121     delete _mutexManager;
00122     _mutexManager = 0;
00123 
00124     delete _logger;
00125     _logger = 0;
00126 
00127 #ifdef USE_SDL_NET
00128     if (_initedSDLnet) SDLNet_Quit();
00129 #endif
00130 
00131     SDL_Quit();
00132 }
00133 
00134 void OSystem_SDL::init() {
00135     // Initialize SDL
00136     initSDL();
00137 
00138 #if !SDL_VERSION_ATLEAST(2, 0, 0)
00139     // Enable unicode support if possible
00140     SDL_EnableUNICODE(1);
00141 #endif
00142 
00143     // Disable OS cursor
00144     SDL_ShowCursor(SDL_DISABLE);
00145 
00146     if (!_logger)
00147         _logger = new Backends::Log::Log(this);
00148 
00149     if (_logger) {
00150         Common::WriteStream *logFile = createLogFile();
00151         if (logFile)
00152             _logger->open(logFile);
00153     }
00154 
00155 
00156     // Creates the early needed managers, if they don't exist yet
00157     // (we check for this to allow subclasses to provide their own).
00158     if (_mutexManager == 0)
00159         _mutexManager = new SdlMutexManager();
00160 
00161     if (_window == 0)
00162         _window = new SdlWindow();
00163 
00164 #if defined(USE_TASKBAR)
00165     if (_taskbarManager == 0)
00166         _taskbarManager = new Common::TaskbarManager();
00167 #endif
00168 
00169 }
00170 
00171 bool OSystem_SDL::hasFeature(Feature f) {
00172 #if SDL_VERSION_ATLEAST(2, 0, 0)
00173     if (f == kFeatureClipboardSupport) return true;
00174 #endif
00175     if (f == kFeatureJoystickDeadzone || f == kFeatureKbdMouseSpeed) {
00176         bool joystickSupportEnabled = ConfMan.getInt("joystick_num") >= 0;
00177         return joystickSupportEnabled;
00178     }
00179     return ModularBackend::hasFeature(f);
00180 }
00181 
00182 void OSystem_SDL::initBackend() {
00183     // Check if backend has not been initialized
00184     assert(!_inited);
00185 
00186 #if SDL_VERSION_ATLEAST(2, 0, 0)
00187     const char *sdlDriverName = SDL_GetCurrentVideoDriver();
00188 #else
00189     const int maxNameLen = 20;
00190     char sdlDriverName[maxNameLen];
00191     sdlDriverName[0] = '\0';
00192     SDL_VideoDriverName(sdlDriverName, maxNameLen);
00193 #endif
00194     // Using printf rather than debug() here as debug()/logging
00195     // is not active by this point.
00196     debug(1, "Using SDL Video Driver \"%s\"", sdlDriverName);
00197 
00198 // ResidualVM specific code start
00199     detectDesktopResolution();
00200 #ifdef USE_OPENGL
00201     detectFramebufferSupport();
00202 #endif
00203 // ResidualVM specific code end
00204 
00205     // Create the default event source, in case a custom backend
00206     // manager didn't provide one yet.
00207     if (_eventSource == 0)
00208         _eventSource = new ResVmSdlEventSource(); // ResidualVm: was SdlEventSource
00209 
00210     if (_eventManager == nullptr) {
00211         DefaultEventManager *eventManager = new DefaultEventManager(_eventSource);
00212 #if SDL_VERSION_ATLEAST(2, 0, 0)
00213         // SDL 2 generates its own keyboard repeat events.
00214         eventManager->setGenerateKeyRepeatEvents(false);
00215 #endif
00216         _eventManager = eventManager;
00217     }
00218 
00219     if (_graphicsManager == 0) {
00220         if (_graphicsManager == 0) {
00221             _graphicsManager = new SurfaceSdlGraphicsManager(_eventSource, _window, _capabilities);
00222         }
00223     }
00224 
00225     if (_savefileManager == 0)
00226         _savefileManager = new DefaultSaveFileManager();
00227 
00228     if (_mixerManager == 0) {
00229         _mixerManager = new SdlMixerManager();
00230         // Setup and start mixer
00231         _mixerManager->init();
00232     }
00233 
00234 #ifdef ENABLE_EVENTRECORDER
00235     g_eventRec.registerMixerManager(_mixerManager);
00236 
00237     g_eventRec.registerTimerManager(new SdlTimerManager());
00238 #else
00239     if (_timerManager == 0)
00240         _timerManager = new SdlTimerManager();
00241 #endif
00242 
00243     _audiocdManager = createAudioCDManager();
00244 
00245     // Setup a custom program icon.
00246     _window->setupIcon();
00247 
00248     _inited = true;
00249 
00250     ModularBackend::initBackend();
00251 
00252     // We have to initialize the graphics manager before the event manager
00253     // so the virtual keyboard can be initialized, but we have to add the
00254     // graphics manager as an event observer after initializing the event
00255     // manager.
00256     dynamic_cast<SdlGraphicsManager *>(_graphicsManager)->activateManager();
00257 }
00258 
00259 // ResidualVM specific code
00260 void OSystem_SDL::detectDesktopResolution() {
00261 #if SDL_VERSION_ATLEAST(2, 0, 0)
00262     SDL_DisplayMode displayMode;
00263     if (!SDL_GetDesktopDisplayMode(0, &displayMode)) {
00264         _capabilities.desktopWidth = displayMode.w;
00265         _capabilities.desktopHeight = displayMode.h;
00266     }
00267 #else
00268     // Query the desktop resolution. We simply hope nothing tried to change
00269     // the resolution so far.
00270     const SDL_VideoInfo *videoInfo = SDL_GetVideoInfo();
00271     if (videoInfo && videoInfo->current_w > 0 && videoInfo->current_h > 0) {
00272         _capabilities.desktopWidth = videoInfo->current_w;
00273         _capabilities.desktopHeight = videoInfo->current_h;
00274     }
00275 #endif
00276 }
00277 
00278 #ifdef USE_OPENGL
00279 void OSystem_SDL::detectFramebufferSupport() {
00280     _capabilities.openGLFrameBuffer = false;
00281 #if defined(USE_GLES2)
00282     // Framebuffers are always available with GLES2
00283     _capabilities.openGLFrameBuffer = true;
00284 #elif !defined(AMIGAOS)
00285     // Spawn a 32x32 window off-screen with a GL context to test if framebuffers are supported
00286 #if SDL_VERSION_ATLEAST(2, 0, 0)
00287     SDL_Window *window = SDL_CreateWindow("", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 32, 32, SDL_WINDOW_OPENGL | SDL_WINDOW_HIDDEN);
00288     if (window) {
00289         SDL_GLContext glContext = SDL_GL_CreateContext(window);
00290         if (glContext) {
00291             OpenGLContext.initialize(OpenGL::kContextGL);
00292             _capabilities.openGLFrameBuffer = OpenGLContext.framebufferObjectSupported;
00293             OpenGLContext.reset();
00294             SDL_GL_DeleteContext(glContext);
00295         }
00296         SDL_DestroyWindow(window);
00297     }
00298 #else
00299     SDL_putenv(const_cast<char *>("SDL_VIDEO_WINDOW_POS=9000,9000"));
00300     SDL_SetVideoMode(32, 32, 0, SDL_OPENGL);
00301     SDL_putenv(const_cast<char *>("SDL_VIDEO_WINDOW_POS=center"));
00302     OpenGLContext.initialize(OpenGL::kContextGL);
00303     _capabilities.openGLFrameBuffer = OpenGLContext.framebufferObjectSupported;
00304     OpenGLContext.reset();
00305 #endif
00306 #endif
00307 }
00308 #endif // USE_OPENGL
00309 // End of ResidualVM specific code
00310 
00311 void OSystem_SDL::engineInit() {
00312 #ifdef USE_TASKBAR
00313     // Add the started engine to the list of recent tasks
00314     _taskbarManager->addRecent(ConfMan.getActiveDomainName(), ConfMan.get("description"));
00315 
00316     // Set the overlay icon the current running engine
00317     _taskbarManager->setOverlayIcon(ConfMan.getActiveDomainName(), ConfMan.get("description"));
00318 #endif
00319 }
00320 
00321 void OSystem_SDL::engineDone() {
00322 #ifdef USE_TASKBAR
00323     // Remove overlay icon
00324     _taskbarManager->setOverlayIcon("", "");
00325 #endif
00326 }
00327 
00328 void OSystem_SDL::initSDL() {
00329     // Check if SDL has not been initialized
00330     if (!_initedSDL) {
00331         // We always initialize the video subsystem because we will need it to
00332         // be initialized before the graphics managers to retrieve the desktop
00333         // resolution, for example. WebOS also requires this initialization
00334         // or otherwise the application won't start.
00335         uint32 sdlFlags = SDL_INIT_VIDEO;
00336 
00337         if (ConfMan.hasKey("disable_sdl_parachute"))
00338             sdlFlags |= SDL_INIT_NOPARACHUTE;
00339 
00340         // Initialize SDL (SDL Subsystems are initiliazed in the corresponding sdl managers)
00341         if (SDL_Init(sdlFlags) == -1)
00342             error("Could not initialize SDL: %s", SDL_GetError());
00343 
00344         _initedSDL = true;
00345     }
00346 
00347 #ifdef USE_SDL_NET
00348     // Check if SDL_net has not been initialized
00349     if (!_initedSDLnet) {
00350         // Initialize SDL_net
00351         if (SDLNet_Init() == -1)
00352             error("Could not initialize SDL_net: %s", SDLNet_GetError());
00353 
00354         _initedSDLnet = true;
00355     }
00356 #endif
00357 }
00358 
00359 void OSystem_SDL::addSysArchivesToSearchSet(Common::SearchSet &s, int priority) {
00360 
00361 #ifdef DATA_PATH
00362     // Add the global DATA_PATH to the directory search list
00363     // FIXME: We use depth = 4 for now, to match the old code. May want to change that
00364     Common::FSNode dataNode(DATA_PATH);
00365     if (dataNode.exists() && dataNode.isDirectory()) {
00366         s.add(DATA_PATH, new Common::FSDirectory(dataNode, 4), priority);
00367     }
00368 #endif
00369 
00370 }
00371 
00372 void OSystem_SDL::setWindowCaption(const char *caption) {
00373     Common::String cap;
00374     byte c;
00375 
00376     // The string caption is supposed to be in LATIN-1 encoding.
00377     // SDL expects UTF-8. So we perform the conversion here.
00378     while ((c = *(const byte *)caption++)) {
00379         if (c < 0x80)
00380             cap += c;
00381         else {
00382             cap += 0xC0 | (c >> 6);
00383             cap += 0x80 | (c & 0x3F);
00384         }
00385     }
00386 
00387     _window->setWindowCaption(cap);
00388 }
00389 
00390 // ResidualVM specific code
00391 void OSystem_SDL::setupScreen(uint screenW, uint screenH, bool fullscreen, bool accel3d) {
00392 #ifdef USE_OPENGL
00393     bool switchedManager = false;
00394     if (accel3d && !dynamic_cast<OpenGLSdlGraphicsManager *>(_graphicsManager)) {
00395         switchedManager = true;
00396     } else if (!accel3d && !dynamic_cast<SurfaceSdlGraphicsManager *>(_graphicsManager)) {
00397         switchedManager = true;
00398     }
00399 
00400     if (switchedManager) {
00401         SdlGraphicsManager *sdlGraphicsManager = dynamic_cast<SdlGraphicsManager *>(_graphicsManager);
00402         sdlGraphicsManager->deactivateManager();
00403         delete _graphicsManager;
00404 
00405         if (accel3d) {
00406             _graphicsManager = sdlGraphicsManager = new OpenGLSdlGraphicsManager(_eventSource, _window, _capabilities);
00407         } else {
00408             _graphicsManager = sdlGraphicsManager = new SurfaceSdlGraphicsManager(_eventSource, _window, _capabilities);
00409         }
00410         sdlGraphicsManager->activateManager();
00411     }
00412 #endif
00413 
00414     ModularBackend::setupScreen(screenW, screenH, fullscreen, accel3d);
00415 }
00416 
00417 void OSystem_SDL::launcherInitSize(uint w, uint h) {
00418     Common::String rendererConfig = ConfMan.get("renderer");
00419     Graphics::RendererType desiredRendererType = Graphics::parseRendererTypeCode(rendererConfig);
00420     Graphics::RendererType matchingRendererType = Graphics::getBestMatchingAvailableRendererType(desiredRendererType);
00421 
00422     bool fullscreen = ConfMan.getBool("fullscreen");
00423 
00424     setupScreen(w, h, fullscreen, matchingRendererType != Graphics::kRendererTypeTinyGL);
00425 }
00426 // End of ResidualVM specific code
00427 
00428 void OSystem_SDL::quit() {
00429     destroy();
00430     exit(0);
00431 }
00432 
00433 void OSystem_SDL::fatalError() {
00434     destroy();
00435     exit(1);
00436 }
00437 
00438 
00439 void OSystem_SDL::logMessage(LogMessageType::Type type, const char *message) {
00440     // First log to stdout/stderr
00441     FILE *output = 0;
00442 
00443     if (type == LogMessageType::kInfo || type == LogMessageType::kDebug)
00444         output = stdout;
00445     else
00446         output = stderr;
00447 
00448     fputs(message, output);
00449     fflush(output);
00450 
00451     // Then log into file (via the logger)
00452     if (_logger)
00453         _logger->print(message);
00454 }
00455 
00456 Common::String OSystem_SDL::getSystemLanguage() const {
00457 #if defined(USE_DETECTLANG) && !defined(WIN32)
00458     // Activating current locale settings
00459     const Common::String locale = setlocale(LC_ALL, "");
00460 
00461     // Restore default C locale to prevent issues with
00462     // portability of sscanf(), atof(), etc.
00463     // See bug #3615148
00464     setlocale(LC_ALL, "C");
00465 
00466     // Detect the language from the locale
00467     if (locale.empty()) {
00468         return ModularBackend::getSystemLanguage();
00469     } else {
00470         int length = 0;
00471 
00472         // Strip out additional information, like
00473         // ".UTF-8" or the like. We do this, since
00474         // our translation languages are usually
00475         // specified without any charset information.
00476         for (int size = locale.size(); length < size; ++length) {
00477             // TODO: Check whether "@" should really be checked
00478             // here.
00479             if (locale[length] == '.' || locale[length] == ' ' || locale[length] == '@')
00480                 break;
00481         }
00482 
00483         return Common::String(locale.c_str(), length);
00484     }
00485 #else // USE_DETECTLANG
00486     return ModularBackend::getSystemLanguage();
00487 #endif // USE_DETECTLANG
00488 }
00489 
00490 bool OSystem_SDL::hasTextInClipboard() {
00491 #if SDL_VERSION_ATLEAST(2, 0, 0)
00492     return SDL_HasClipboardText() == SDL_TRUE;
00493 #else
00494     return false;
00495 #endif
00496 }
00497 
00498 Common::String OSystem_SDL::getTextFromClipboard() {
00499     if (!hasTextInClipboard()) return "";
00500 
00501 #if SDL_VERSION_ATLEAST(2, 0, 0)
00502     char *text = SDL_GetClipboardText();
00503     // The string returned by SDL is in UTF-8. Convert to the
00504     // current TranslationManager encoding or ISO-8859-1.
00505 #ifdef USE_TRANSLATION
00506     char *conv_text = SDL_iconv_string(TransMan.getCurrentCharset().c_str(), "UTF-8", text, SDL_strlen(text) + 1);
00507 #else
00508     char *conv_text = SDL_iconv_string("ISO-8859-1", "UTF-8", text, SDL_strlen(text) + 1);
00509 #endif
00510     if (conv_text) {
00511         SDL_free(text);
00512         text = conv_text;
00513     }
00514     Common::String strText = text;
00515     SDL_free(text);
00516 
00517     return strText;
00518 #else
00519     return "";
00520 #endif
00521 }
00522 
00523 bool OSystem_SDL::setTextInClipboard(const Common::String &text) {
00524 #if SDL_VERSION_ATLEAST(2, 0, 0)
00525     // The encoding we need to use is UTF-8. Assume we currently have the
00526     // current TranslationManager encoding or ISO-8859-1.
00527 #ifdef USE_TRANSLATION
00528     char *utf8_text = SDL_iconv_string("UTF-8", TransMan.getCurrentCharset().c_str(), text.c_str(), text.size() + 1);
00529 #else
00530     char *utf8_text = SDL_iconv_string("UTF-8", "ISO-8859-1", text.c_str(), text.size() + 1);
00531 #endif
00532     if (utf8_text) {
00533         int status = SDL_SetClipboardText(utf8_text);
00534         SDL_free(utf8_text);
00535         return status == 0;
00536     }
00537     return SDL_SetClipboardText(text.c_str()) == 0;
00538 #else
00539     return false;
00540 #endif
00541 }
00542 
00543 uint32 OSystem_SDL::getMillis(bool skipRecord) {
00544     uint32 millis = SDL_GetTicks();
00545 
00546 #ifdef ENABLE_EVENTRECORDER
00547     g_eventRec.processMillis(millis, skipRecord);
00548 #endif
00549 
00550     return millis;
00551 }
00552 
00553 void OSystem_SDL::delayMillis(uint msecs) {
00554 #ifdef ENABLE_EVENTRECORDER
00555     if (!g_eventRec.processDelayMillis())
00556 #endif
00557         SDL_Delay(msecs);
00558 }
00559 
00560 void OSystem_SDL::getTimeAndDate(TimeDate &td) const {
00561     time_t curTime = time(0);
00562     struct tm t = *localtime(&curTime);
00563     td.tm_sec = t.tm_sec;
00564     td.tm_min = t.tm_min;
00565     td.tm_hour = t.tm_hour;
00566     td.tm_mday = t.tm_mday;
00567     td.tm_mon = t.tm_mon;
00568     td.tm_year = t.tm_year;
00569     td.tm_wday = t.tm_wday;
00570 }
00571 
00572 Audio::Mixer *OSystem_SDL::getMixer() {
00573     assert(_mixerManager);
00574     return getMixerManager()->getMixer();
00575 }
00576 
00577 SdlMixerManager *OSystem_SDL::getMixerManager() {
00578     assert(_mixerManager);
00579 
00580 #ifdef ENABLE_EVENTRECORDER
00581     return g_eventRec.getMixerManager();
00582 #else
00583     return _mixerManager;
00584 #endif
00585 }
00586 
00587 Common::TimerManager *OSystem_SDL::getTimerManager() {
00588 #ifdef ENABLE_EVENTRECORDER
00589     return g_eventRec.getTimerManager();
00590 #else
00591     return _timerManager;
00592 #endif
00593 }
00594 
00595 AudioCDManager *OSystem_SDL::createAudioCDManager() {
00596     // Audio CD support was removed with SDL 2.0
00597 #if SDL_VERSION_ATLEAST(2, 0, 0)
00598     return new DefaultAudioCDManager();
00599 #else
00600     return new SdlAudioCDManager();
00601 #endif
00602 }
00603 
00604 Common::SaveFileManager *OSystem_SDL::getSavefileManager() {
00605 #ifdef ENABLE_EVENTRECORDER
00606     return g_eventRec.getSaveManager(_savefileManager);
00607 #else
00608     return _savefileManager;
00609 #endif
00610 }
00611 
00612 //Not specified in base class
00613 Common::String OSystem_SDL::getScreenshotsPath() {
00614     Common::String path = ConfMan.get("screenshotpath");
00615     if (!path.empty() && !path.hasSuffix("/"))
00616         path += "/";
00617     return path;
00618 }


Generated on Sat May 25 2019 05:00:53 for ResidualVM by doxygen 1.7.1
curved edge   curved edge