OSDLBasic.cc

Go to the documentation of this file.
00001 #include "OSDLBasic.h"
00002 
00003 #include "OSDLEvents.h"             // for event module
00004 #include "OSDLVideo.h"              // for video module
00005 #include "OSDLCDROMDriveHandler.h"  // for CD-ROM drive handler
00006 
00007 #include "OSDLAudio.h"              // for audio module
00008 
00009 #include "OSDLUtils.h"              // for getBackendLastError
00010 
00011 
00012 #include "SDL.h"                    // for SDL_Init, etc.
00013 
00014 #include <list>
00015 
00016 
00017 #ifdef OSDL_USES_CONFIG_H
00018 #include <OSDLConfig.h>             // for the actual OSDL_LIBTOOL_VERSION
00019 #endif // OSDL_USES_CONFIG_H
00020 
00021 
00022 
00023 using std::string ;
00024 
00025 using namespace Ceylan ;
00026 using namespace Ceylan::Log ;
00027 
00028 using namespace OSDL ;
00029 
00030 
00031 // Backend section.
00032     
00033 const CommonModule::BackendReturnCode CommonModule::BackendSuccess =  0 ;
00034 const CommonModule::BackendReturnCode CommonModule::BackendError   = -1 ;
00035 
00036 
00037 // Tells whether the SDL backend is initialized (SDL_Init called).
00038 bool CommonModule::_BackendInitialized = false ;
00039 
00040 
00041 // Allows to debug OSDL version management :
00042 #define OSDL_DEBUG_VERSION 0
00043 
00044 const Ceylan::LibtoolVersion & OSDL::GetVersion() throw()
00045 {
00046 
00047 
00048 #if OSDL_DEBUG_VERSION
00049 
00050     // Intentional memory leak :
00051     
00052     Ceylan::LibtoolVersion * ceylanVersion ;
00053     
00054     try
00055     {
00056         osdlVersion = new Ceylan::LibtoolVersion( OSDL_LIBTOOL_VERSION ) ;
00057     }
00058     catch( const Ceylan::Exception & e )
00059     {
00060         Ceylan::emergencyShutdown( "OSDL::GetVersion failed : "
00061             + e.toString() ) ;
00062     }   
00063         
00064     return *osdlVersion ;
00065 
00066 
00067 #else // OSDL_DEBUG_VERSION
00068 
00069     static Ceylan::LibtoolVersion osdlVersion( OSDL_LIBTOOL_VERSION ) ;
00070     return osdlVersion ;
00071 
00072 #endif // OSDL_DEBUG_VERSION    
00073     
00074 }
00075 
00076 
00077 
00078 /*
00079  * These flags are to be used with getCommonModule to specify which submodules 
00080  * and settings should be used.
00081  *
00082  * A flag specifying that the application required event management could 
00083  * be added : UseJoystick could be complemented with UseKeyboard and 
00084  * UseMouse, and UseEvents would be internally activated iff UseJoystick,
00085  * UseKeyboard or UseMouse (or even UseEventThread) were activated.
00086  *
00087  * @note They are defined relatively as SDL back-end.
00088  *
00089  */
00090 
00091 const Ceylan::Flags CommonModule::UseTimer       = SDL_INIT_TIMER  ;
00092 const Ceylan::Flags CommonModule::UseAudio       = SDL_INIT_AUDIO  ;
00093 const Ceylan::Flags CommonModule::UseVideo       = SDL_INIT_VIDEO  ;
00094 const Ceylan::Flags CommonModule::UseCDROM       = SDL_INIT_CDROM  ;
00095 const Ceylan::Flags CommonModule::UseJoystick    = SDL_INIT_JOYSTICK  ;
00096 const Ceylan::Flags CommonModule::UseKeyboard    = 0x4000 ;
00097 const Ceylan::Flags CommonModule::UseMouse       = 0x8000 ;
00098 const Ceylan::Flags CommonModule::UseEverything  = SDL_INIT_EVERYTHING  ;
00099 const Ceylan::Flags CommonModule::NoParachute    = SDL_INIT_NOPARACHUTE ;
00100 const Ceylan::Flags CommonModule::UseEventThread = SDL_INIT_EVENTTHREAD ;
00101 
00102 
00103 /*
00104  * Warning : OSDL added flags (if SDL adds flags, they might collide and 
00105  * create awkward bugs) : see 'testOSDLBasic' to check their value.
00106  *
00107  * SDL_INIT_TIMER       : 0x00000001 = 0b00000000000000000000000000000001
00108  * SDL_INIT_AUDIO       : 0x00000010 = 0b00000000000000000000000000010000
00109  * SDL_INIT_VIDEO       : 0x00000020 = 0b00000000000000000000000000100000
00110  * SDL_INIT_CDROM       : 0x00000100 = 0b00000000000000000000000100000000
00111  * SDL_INIT_JOYSTICK    : 0x00000200 = 0b00000000000000000000001000000000
00112  * UseKeyboard          : 0x4000     = 0b00000000000000000100000000000000
00113  * UseMouse             : 0x8000     = 0b00000000000000001000000000000000
00114  * SDL_INIT_EVERYTHING  : 0x0000FFFF = 0b00000000000000001111111111111111
00115  * SDL_INIT_NOPARACHUTE : 0x00100000 = 0b00000000000100000000000000000000
00116  * SDL_INIT_EVENTTHREAD : 0x01000000 = 0b00000001000000000000000000000000
00117  *
00118  */
00119 
00120 
00121 CommonModule * CommonModule::_CurrentCommonModule = 0 ;
00122 
00123 
00125 string CommonModule::_SDLEnvironmentVariables[] = 
00126 {
00127         "SDL_DEBUG",
00128         "SDL_CDROM"
00129 } ;
00130 
00131 
00132 CommonModule::CommonModule( Flags flags ) throw ( OSDL::Exception ) : 
00133     Ceylan::Module( 
00134         "OSDL common module",
00135         "This is the root module of OSDL",
00136         "http://osdl.sourceforge.net",
00137         "Olivier Boudeville",
00138         "olivier.boudeville@online.fr",
00139         OSDL::GetVersion(),
00140         "LGPL" ),       
00141     _video( 0 ), 
00142     _events( 0 ), 
00143     _audio( 0 ), 
00144     _flags( flags ),
00145     _cdromHandler( 0 ) 
00146 {
00147 
00148      
00149     send( "Starting OSDL version " + OSDL::GetVersion().toString() + ". " 
00150         + InterpretFlags( flags ) ) ; 
00151                 
00152     /*
00153      * UseEverything flag is 0x0000FFFF, therefore not to be specifically
00154      * managed.
00155      *
00156      * Moreover, the flags should have been already fixed thanks to the
00157      * AutoCorrectFlags method, so no more interpretation is needed.
00158      *
00159      */
00160     
00161     if ( flags & UseTimer ) 
00162     {
00163         send( "Initializing timer subsystem" ) ;
00164         if ( SDL_InitSubSystem( UseTimer ) != BackendSuccess ) 
00165             throw OSDL::Exception( "CommonModule constructor : "
00166                 "unable to initialize timer subsystem : " 
00167                 + Utils::getBackendLastError() ) ;
00168         send( "Timer subsystem initialized" ) ;             
00169     }
00170     
00171     
00172     if ( flags & UseCDROM ) 
00173     {
00174         _cdromHandler = new OSDL::CDROMDriveHandler() ;
00175     }
00176     
00177     
00178     if ( flags & NoParachute ) 
00179     {
00180         send( "Disabling SDL parachute" ) ;
00181         if ( SDL_InitSubSystem( NoParachute ) != BackendSuccess )
00182             throw OSDL::Exception( "CommonModule constructor : "
00183                 "unable to disable SDL parachute : " 
00184                 + Utils::getBackendLastError() ) ;
00185         send( "SDL parachute initialized" ) ;               
00186     }
00187     
00188             
00189     /*
00190      * @fixme Events must imply video. There seems to exist no way 
00191      * of requesting specifically events. Currently video and event 
00192      * support are synonym features.
00193      *
00194      * @fixme On some platforms (ex : Windows), audio may not work if 
00195      * no video mode is initialized.
00196      * Hence audio would imply video (to be checked).
00197      *
00198      */
00199                 
00200     if ( flags & UseVideo ) 
00201     {
00202         _video = new Video::VideoModule() ;
00203         send( "Video support demanded, adding Events support" ) ;
00204         _events = new Events::EventsModule( flags ) ;       
00205     }
00206     
00207     
00208     /*
00209      * Video must be initialized *before* audio (to rely on a window handle) 
00210      * on some platforms :
00211      *
00212      */ 
00213     if ( flags & UseAudio )
00214     {
00215         _audio = new Audio::AudioModule() ;
00216     }   
00217     
00218     
00219     _BackendInitialized = true ;
00220     
00221     send( "OSDL successfully initialized" ) ;
00222     
00223     dropIdentifier() ;
00224     
00225 }
00226 
00227 
00228 CommonModule::~CommonModule() throw ()
00229 {   
00230 
00231     send( "Stopping OSDL" ) ;
00232 
00233     if ( _cdromHandler != 0 )
00234     {
00235         delete _cdromHandler ;
00236         _cdromHandler = 0 ; 
00237     }
00238         
00239     if ( _audio != 0 )
00240     {
00241         delete _audio ;
00242         _audio = 0 ;
00243     }   
00244     
00245     if ( _events != 0 )
00246     {
00247         delete _events ;
00248         _events = 0 ;
00249     }   
00250     
00251     if ( _video != 0 )
00252     {
00253         delete _video ;
00254         _video = 0 ;
00255     }   
00256             
00257     SDL_Quit() ;
00258     
00259     send( "OSDL successfully stopped" ) ;       
00260     
00261 }
00262 
00263 
00264 string CommonModule::InterpretFlags( Flags flags ) throw() 
00265 {
00266 
00267     std::list<string> res ;
00268         
00269     if ( flags & UseTimer )
00270         res.push_back( "Timer requested (UseTimer is set)." ) ;
00271     else
00272         res.push_back( "No timer requested (UseTimer is not set)." ) ;
00273         
00274     if ( flags & UseAudio)  
00275         res.push_back( "Audio requested (UseAudio is set)." ) ;
00276     else
00277         res.push_back( "No audio requested (UseAudio is not set)." ) ;
00278         
00279     if ( flags & UseVideo )
00280         res.push_back( "Video requested (UseVideo is set)." ) ;
00281     else
00282         res.push_back( "No video requested (UseVideo is not set)." ) ;
00283         
00284     if ( flags & UseCDROM )
00285         res.push_back( "CD-ROM support requested (UseCDROM is set)." ) ;
00286     else
00287         res.push_back( "No CD-ROM support requested "
00288             "(UseCDROM is not set)." ) ;
00289         
00290         
00291     if ( flags & UseJoystick )
00292         res.push_back( "Joystick support requested (UseJoystick is set)." ) ;
00293     else
00294         res.push_back( "No joystick support requested "
00295             "(UseJoystick is not set)." ) ;
00296         
00297     if ( flags & UseKeyboard )
00298         res.push_back( "Keyboard support requested (UseKeyboard is set)." ) ;
00299     else
00300         res.push_back( "No keyboard support requested "
00301             "(UseKeyboard is not set)." ) ;
00302         
00303     if ( flags & UseMouse )
00304         res.push_back( "Mouse support requested (UseMouse is set)." ) ;
00305     else
00306         res.push_back( "No mouse support requested (UseMouse is not set)." ) ;
00307         
00308         
00309     if ( ( flags & UseEverything ) == UseEverything )
00310         res.push_back( "Every subsystem is requested "
00311             "(UseEverything is set)." ) ;
00312     else
00313         res.push_back( "Not all subsystems are requested "
00314             "(UseEverything is not set)." ) ;
00315         
00316     if ( flags & NoParachute )
00317         res.push_back( "No catching of fatal signals requested "
00318             "(NoParachute is set)." ) ;
00319     else
00320         res.push_back( "Fatal signal will be caught "
00321             "(NoParachute is not set)." ) ;
00322         
00323     if ( flags & UseEventThread )
00324         res.push_back( "Event thread requested (UseEventThread is set)." ) ;
00325     else
00326         res.push_back( "No event thread requested "
00327             "(UseEventThread is not set)." ) ;
00328         
00329 
00330     return "The specified flags for Common module, whose value is " 
00331         + Ceylan::toString( flags, /* bit field */ true ) 
00332         + ", mean : " + Ceylan::formatStringList( res ) ;
00333 
00334 }
00335 
00336 
00337 bool CommonModule::hasVideoModule() const throw()
00338 {
00339     return ( _video != 0 ) ;
00340 }
00341 
00342 
00343 Video::VideoModule & CommonModule::getVideoModule() const 
00344     throw( OSDL::Exception )
00345 {
00346 
00347     if ( _video == 0 )
00348         throw OSDL::Exception( 
00349             "CommonModule::getVideoModule : no video module available." ) ;
00350     
00351     return * _video ;
00352     
00353 }
00354 
00355 
00356 
00357 bool CommonModule::hasEventsModule() const throw()
00358 {
00359     return ( _events != 0 ) ;
00360 }
00361 
00362 
00363 Events::EventsModule & CommonModule::getEventsModule() const 
00364     throw( OSDL::Exception )
00365 {
00366 
00367     if ( _events == 0 )
00368         throw OSDL::Exception( 
00369             "CommonModule::getEventsModule : no events module available." ) ;
00370     
00371     return * _events ;
00372     
00373 }
00374 
00375 
00376 
00377 bool CommonModule::hasAudioModule() const throw()
00378 {
00379     return ( _audio != 0 ) ;
00380 }
00381  
00382  
00383 Audio::AudioModule & CommonModule::getAudioModule() const 
00384     throw( OSDL::Exception )
00385 {
00386 
00387     if ( _audio == 0 )
00388         throw OSDL::Exception( 
00389             "CommonModule::getAudioModule : no audio module available." ) ;
00390     
00391     return * _audio ;
00392     
00393 }
00394 
00395 
00396 
00397 Flags CommonModule::getFlags() const throw()
00398 {
00399     return _flags ;
00400 } 
00401 
00402 
00403 
00404 bool CommonModule::hasCDROMDriveHandler() const throw()
00405 {
00406     return ( _cdromHandler != 0 ) ;
00407 }
00408 
00409         
00410 CDROMDriveHandler & CommonModule::getCDROMDriveHandler() 
00411     const throw( OSDL::Exception )
00412 {
00413 
00414     if ( _cdromHandler == 0 )
00415         throw OSDL::Exception( "CommonModule::getCDROMDriveHandler : "
00416             "no CD-ROM handler available." ) ;
00417     
00418     return * _cdromHandler ;
00419 
00420 }
00421 
00422 
00423 const string CommonModule::toString( Ceylan::VerbosityLevels level ) 
00424     const throw()
00425 {
00426     
00427     string res = "Common root module, with currently video module " ;
00428         
00429     if ( _video != 0 )
00430         res += "enabled" ;
00431     else
00432         res += "disabled" ;
00433         
00434     res += ", with event module " ;
00435     
00436     if ( _events != 0 )
00437         res += "enabled" ;
00438     else
00439         res += "disabled" ;
00440         
00441     res += ", with audio module " ;
00442     
00443     if ( _audio != 0 )
00444         res += "enabled" ;
00445     else
00446         res += "disabled" ;
00447     
00448     res += ", using " ;
00449     
00450     if ( _cdromHandler != 0 )
00451         res += "a" ;
00452     else    
00453         res += "no" ;
00454         
00455     res += " CD-ROM handler" ;  
00456     
00457     if ( level == Ceylan::low )
00458         return res ;
00459             
00460             
00461     res += ". " + InterpretFlags( _flags ) ;
00462         
00463     if ( level == Ceylan::medium )
00464         return res ;
00465     
00466     std::list<string> completeMessage ;
00467     
00468     completeMessage.push_back( res ) ;
00469     
00470     completeMessage.push_back( Ceylan::Module::toString()  ) ;
00471     
00472     completeMessage.push_back( 
00473         "The version of the Ceylan library currently linked is " 
00474         + Ceylan::GetVersion().toString() + "." ) ;
00475         
00476     completeMessage.push_back( 
00477         "The version of the OSDL library currently linked is " 
00478         + OSDL::GetVersion().toString() + "." ) ;
00479     
00480     return Ceylan::formatStringList( completeMessage ) ;
00481     
00482 }
00483 
00484 
00485 string CommonModule::DescribeEnvironmentVariables() throw()
00486 {
00487 
00488     Ceylan::Uint16 varCount = sizeof( _SDLEnvironmentVariables ) 
00489         / sizeof (char * ) ;
00490     
00491     string result = "Examining the " + Ceylan::toString( varCount )
00492         + " general-purpose environment variables for SDL backend :" ;
00493     
00494     std::list<string> variables ;
00495         
00496     string var, value ;
00497     
00498     bool htmlFormat = Ceylan::TextDisplayable::GetOutputFormat() ;
00499     
00500     for ( Ceylan::Uint16 i = 0; i < varCount; i++ ) 
00501     {
00502     
00503         var = _SDLEnvironmentVariables[ i ] ;
00504         value = Ceylan::System::getEnvironmentVariable( var ) ;
00505         
00506         if ( value.empty() )
00507         {
00508             if ( htmlFormat == Ceylan::TextDisplayable::html )
00509             {
00510                 variables.push_back( "<em>" + var + "</em> is not set." ) ;
00511             }
00512             else
00513             {
00514                 variables.push_back( var + " is not set." ) ;           
00515             }   
00516         }
00517         else
00518         {           
00519             if ( htmlFormat == Ceylan::TextDisplayable::html )
00520             {
00521                 variables.push_back( "<b>" + var + "</b> set to [" 
00522                     + value + "]." ) ;
00523             }
00524             else
00525             {
00526                 variables.push_back( var + " set to [" + value + "]." ) ;
00527             }   
00528         }   
00529     
00530     }
00531     
00532     return result + Ceylan::formatStringList( variables ) ;
00533     
00534 }
00535 
00536 
00537 bool CommonModule::IsBackendInitialized() throw()
00538 {
00539 
00540     return _BackendInitialized ;
00541     
00542 }
00543 
00544 
00545 Flags CommonModule::AutoCorrectFlags( Flags inputFlags ) throw()
00546 {
00547 
00548 
00549     /*
00550      * Event source implies event propagation which implies, with SDL, 
00551      * video being activated :
00552      *
00553      */
00554     
00555     if ( ! ( inputFlags & UseVideo ) )
00556     {
00557     
00558         // Video not selected, are events used ?
00559         
00560         if ( inputFlags & ( UseJoystick | UseKeyboard | UseMouse ) ) 
00561         {
00562         
00563             /*
00564              * Yes, it is abnormal since events implies video. 
00565              * Let's correct that :
00566              *
00567              */
00568             
00569             LogPlug::warning( "CommonModule::AutoCorrectFlags : "
00570                 "at least one input device was selected, "
00571                 "hence event support was requested, "
00572                 "whereas video was not specifically set. " 
00573                 "Since the event loop needs video, "
00574                 "the video subsystem has been automatically enabled." ) ; 
00575                 
00576             inputFlags |= UseVideo ;
00577 
00578         }
00579     
00580     }
00581     
00582     return inputFlags ;
00583         
00584 }
00585 
00586 
00587 
00588 // Friend section :
00589 
00590 
00591 CommonModule & OSDL::getCommonModule( Flags flags ) throw()
00592 {
00593 
00594     // First, auto-correct flags with implied sub-systems, if necessary :
00595     flags = CommonModule::AutoCorrectFlags( flags ) ;
00596             
00597     LogPlug::info( "Retrieving basic common module for OSDL" ) ;
00598     
00599     if ( CommonModule::_CurrentCommonModule == 0 ) 
00600     {
00601     
00602         // if not running, launch OSDL unconditionnally and store it.   
00603         LogPlug::info( 
00604             "OSDL was not running yet, launching basic OSDL with flags "
00605             + Ceylan::toString( flags, /* bitfield */ true ) ) ;
00606         CommonModule::_CurrentCommonModule = new CommonModule( flags ) ;
00607         return * CommonModule::_CurrentCommonModule ;
00608         
00609     }   
00610     else 
00611     {
00612     
00613         // OSDL was already running.
00614         LogPlug::info( "OSDL is already running, comparing demanded flags "
00615             "with flags of the running version." ) ;
00616         
00617         if ( flags == CommonModule::_CurrentCommonModule->getFlags() ) 
00618         {
00619         
00620             /* 
00621              * if requested flags are the same that the ones of the 
00622              * currently running 
00623              * OSDL instance, return currently running OSDL instance.
00624              */
00625              
00626             LogPlug::info( "Flags are matching, "
00627                 "returning already launched basic OSDL module" ) ;
00628                 
00629             return * CommonModule::_CurrentCommonModule ;
00630             
00631         } 
00632         else 
00633         {
00634         
00635             /* 
00636              * Running flags and requested flags do not match.
00637              * Stop current OSDL instance, and re-run OSDL with requested flags.
00638              *
00639              */
00640             LogPlug::info( "Flags do not match, "
00641                 "stopping already launched OSDL root module, "
00642                 "restarting with new flags, returning this new instance" ) ;
00643                 
00644             delete CommonModule::_CurrentCommonModule ;
00645             
00646             CommonModule::_CurrentCommonModule = new CommonModule( flags ) ;
00647             
00648             return * CommonModule::_CurrentCommonModule ;
00649             
00650         }
00651     }   
00652                 
00653 }
00654 
00655 
00656 bool OSDL::hasExistingCommonModule() throw()
00657 {
00658 
00659     return ( CommonModule::_CurrentCommonModule != 0 ) ;
00660     
00661 }
00662 
00663 
00664 CommonModule & OSDL::getExistingCommonModule() throw()
00665 {
00666 
00667     if ( CommonModule::_CurrentCommonModule == 0 ) 
00668         Ceylan::emergencyShutdown( 
00669             "OSDL::getExistingCommonModule : no common module available." ) ;
00670     
00671     return * CommonModule::_CurrentCommonModule ;
00672     
00673 }
00674 
00675 
00676 void OSDL::stop() throw()
00677 {
00678 
00679     if ( CommonModule::_CurrentCommonModule == 0 )
00680     {
00681         LogPlug::error( 
00682             "OSDL::stop has been called whereas OSDL was not running" ) ;
00683     }   
00684     else
00685     {
00686         LogPlug::info( "Stopping launched OSDL module" ) ;
00687         delete CommonModule::_CurrentCommonModule ;
00688         CommonModule::_CurrentCommonModule = 0 ;
00689     }
00690     
00691 }
00692 

Generated on Fri Mar 30 14:46:59 2007 for OSDL by  doxygen 1.5.1