fix indenting.
[gnash.git] / gui / Player.cpp
blob497250d5e554757a2e639d7ab01bf807dccba7da
1 // Player.cpp: Top level SWF player, for gnash.
2 //
3 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Free Software
4 // Foundation, Inc
5 //
6 // This program is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 3 of the License, or
9 // (at your option) any later version.
10 //
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software
18 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 #ifdef HAVE_CONFIG_H
22 #include "gnashconfig.h"
23 #endif
25 #ifndef DEFAULT_GUI
26 # define DEFAULT_GUI "NULL"
27 #endif
29 #include "gui.h"
30 #include "NullGui.h"
32 #include "MovieFactory.h"
33 #include "movie_definition.h"
34 #include "sound_handler.h" // for set_sound_handler and create_sound_handler_*
35 #include "MovieClip.h" // for setting FlashVars
36 #include "movie_root.h"
37 #include "Player.h"
38 #include "StreamProvider.h"
40 #include "swf/TagLoadersTable.h"
41 #include "swf/DefaultTagLoaders.h"
42 #include "NamingPolicy.h"
43 #include "StringPredicates.h"
44 #include "URL.h"
45 #include "rc.h"
46 #include "GnashException.h"
47 #include "noseek_fd_adapter.h"
48 #include "VM.h"
49 #include "SystemClock.h"
51 #ifdef USE_FFMPEG
52 # include "MediaHandlerFfmpeg.h"
53 #elif defined(USE_GST)
54 # include "MediaHandlerGst.h"
55 #elif defined(USE_HAIKU_ENGINE)
56 # include "MediaHandlerHaiku.h"
57 #endif
59 #include "GnashSystemIOHeaders.h" // for write()
60 #include "log.h"
61 #include <iostream>
62 #include <sstream>
63 #include <iomanip>
64 #include <boost/lexical_cast.hpp>
66 using namespace gnash;
68 namespace {
69 gnash::LogFile& dbglogfile = gnash::LogFile::getDefaultInstance();
72 void
73 Player::setFlashVars(const std::string& varstr)
75 typedef Gui::VariableMap maptype;
77 maptype vars;
78 URL::parse_querystring(varstr, vars);
80 _gui->addFlashVars(vars);
83 void
84 Player::setScriptableVar(const std::string &name, const std::string &value)
86 _gui->addScriptableVar(name, value);
89 Player::Player()
91 #if defined(RENDERER_CAIRO)
92 _bitDepth(32),
93 #else
94 _bitDepth(16),
95 #endif
96 _scale(1.0f),
97 _delay(0),
98 _width(0),
99 _height(0),
100 _xPosition(-1),
101 _yPosition(-1),
102 _windowID(0),
103 _doLoop(true),
104 _doRender(true),
105 _doSound(true),
106 _exitTimeout(0),
107 _movieDef(0),
108 _maxAdvances(0),
109 #ifdef GNASH_FPS_DEBUG
110 _fpsDebugTime(0.0),
111 #endif
112 _hostfd(-1),
113 _controlfd(-1),
114 _startFullscreen(false),
115 _hideMenu(false)
117 init();
120 float
121 Player::setScale(float newscale)
123 float oldscale = _scale;
124 _scale = newscale;
125 return oldscale;
128 void
129 Player::init()
131 /// Initialize gnash core library
132 gnashInit();
136 void
137 Player::init_logfile()
139 dbglogfile.setWriteDisk(false);
141 RcInitFile& rcfile = RcInitFile::getDefaultInstance();
142 if (rcfile.useWriteLog()) {
143 dbglogfile.setWriteDisk(true);
146 dbglogfile.setLogFilename(rcfile.getDebugLog());
148 if (rcfile.verbosityLevel() > 0) {
149 dbglogfile.setVerbosity(rcfile.verbosityLevel());
152 if (rcfile.useActionDump()) {
153 dbglogfile.setActionDump(true);
154 dbglogfile.setVerbosity();
157 if (rcfile.useParserDump()) {
158 dbglogfile.setParserDump(true);
159 dbglogfile.setVerbosity();
162 // If a delay was not specified yet use
163 // any eventual setting for it found in
164 // the RcInitFile
166 // TODO: we should remove all uses of the rcfile
167 // from Player class..
169 if (!_delay && rcfile.getTimerDelay() > 0) {
170 _delay = rcfile.getTimerDelay();
171 log_debug (_("Timer delay set to %d milliseconds"), _delay);
176 unsigned int
177 Player::silentStream(void* /*udata*/, boost::int16_t* stream, unsigned int len, bool& atEOF)
179 std::fill(stream, stream+len, 0);
180 atEOF=false;
181 return len;
184 void
185 Player::init_sound()
188 if (_doSound) {
189 try {
190 #ifdef SOUND_SDL
191 _soundHandler.reset(sound::create_sound_handler_sdl(_audioDump));
192 #elif defined(SOUND_GST)
193 _soundHandler.reset(media::create_sound_handler_gst());
194 #elif defined(SOUND_AHI)
195 _soundHandler.reset(sound::create_sound_handler_aos4(_audioDump));
196 #elif defined(SOUND_MKIT)
197 _soundHandler.reset(sound::create_sound_handler_mkit(_audioDump));
198 #else
199 log_error(_("Sound requested but no sound support compiled in"));
200 return;
201 #endif
202 } catch (SoundException& ex) {
203 log_error(_("Could not create sound handler: %s."
204 " Will continue w/out sound."), ex.what());
206 if (! _audioDump.empty()) {
207 // add a silent stream to the audio pool so that our output file
208 // is homogenous; we actually want silent wave data when no sounds
209 // are playing on the stage
210 _soundHandler->attach_aux_streamer(silentStream, (void*) this);
215 void
216 Player::init_media()
218 #ifdef USE_FFMPEG
219 _mediaHandler.reset( new gnash::media::ffmpeg::MediaHandlerFfmpeg() );
220 #elif defined(USE_GST)
221 _mediaHandler.reset( new gnash::media::gst::MediaHandlerGst() );
222 #elif defined(USE_HAIKU_ENGINE)
223 _mediaHandler.reset( new gnash::media::haiku::MediaHandlerHaiku() );
224 #else
225 log_error(_("No media support compiled in"));
226 return;
227 #endif
229 gnash::media::MediaHandler::set(_mediaHandler);
233 void
234 Player::init_gui()
236 if (_doRender) {
237 _gui = getGui();
238 } else {
239 _gui.reset(new NullGui(_doLoop, *_runResources));
242 _gui->setMaxAdvances(_maxAdvances);
244 #ifdef GNASH_FPS_DEBUG
245 if (_fpsDebugTime) {
246 log_debug(_("Activating FPS debugging every %g seconds"),
247 _fpsDebugTime);
248 _gui->setFpsTimerInterval(_fpsDebugTime);
250 #endif
253 boost::intrusive_ptr<movie_definition>
254 Player::load_movie()
256 /// The RunResources must be initialized by this point to provide resources
257 /// for parsing.
258 assert(_runResources.get());
260 boost::intrusive_ptr<gnash::movie_definition> md;
262 RcInitFile& rcfile = RcInitFile::getDefaultInstance();
263 URL vurl(_url);
265 if (vurl.protocol() == "file") {
266 const std::string& path = vurl.path();
267 size_t lastSlash = path.find_last_of('/');
268 std::string dir = path.substr(0, lastSlash+1);
269 rcfile.addLocalSandboxPath(dir);
270 log_debug(_("%s appended to local sandboxes"), dir.c_str());
273 try {
274 if ( _infile == "-" ) {
275 std::auto_ptr<IOChannel> in (
276 noseek_fd_adapter::make_stream(fileno(stdin)));
277 md = MovieFactory::makeMovie(in, _url, *_runResources, false);
278 } else {
279 URL url(_infile);
280 if ( url.protocol() == "file" ) {
281 std::string path = url.path();
282 // We'll need to allow load of the file, no matter virtual url
283 // specified...
284 // This is kind of hackish, cleaner would be adding an argument
285 // to createMovie to skip the security checking phase.
286 // NOTE that if we fail to allow this load, the konqueror plugin
287 // would not be able to load anything
289 rcfile.addLocalSandboxPath(path);
290 log_debug(_("%s appended to local sandboxes"), path.c_str());
293 // _url should be always set at this point...
294 md = MovieFactory::makeMovie(url, *_runResources, _url.c_str(),
295 false);
297 } catch (const GnashException& er) {
298 std::cerr << er.what() << std::endl;
299 md = NULL;
302 if ( ! md ) {
303 fprintf(stderr, "Could not load movie '%s'\n", _infile.c_str());
304 return NULL;
307 return md;
310 /// \brief Run, used to open a new flash file. Using previous initialization
312 Player::run(int argc, char* argv[], const std::string& infile,
313 const std::string& url)
315 printf("FIXME: %d\n", __LINE__);
317 // Call this at run() time, so the caller has
318 // a cache of setting some parameter before calling us...
319 // (example: setDoSound(), setWindowId() etc.. )
320 init_logfile();
321 init_media();
322 init_sound();
324 // gnash.cpp should check that a filename is supplied.
325 assert (!infile.empty());
327 _infile = infile;
329 printf("FIXME: %d\n", __LINE__);
331 // Work out base url
332 if (_baseurl.empty()) {
333 if (!url.empty()) _baseurl = url;
334 else if (infile == "-") _baseurl = URL("./").str();
335 else _baseurl = infile;
338 // Set _root._url (either explicit of from infile)
339 if (!url.empty()) {
340 _url = url;
341 } else {
342 _url = infile;
345 // Parse player parameters. These are not passed to the SWF, but rather
346 // control stage properties etc.
347 Params::const_iterator it = _params.find("base");
348 const URL baseURL = (it == _params.end()) ? _baseurl :
349 URL(it->second, _baseurl);
351 /// The RunResources should be populated before parsing.
352 _runResources.reset(new RunResources(baseURL.str()));
353 _runResources->setSoundHandler(_soundHandler);
355 boost::shared_ptr<SWF::TagLoadersTable> loaders(new SWF::TagLoadersTable());
356 addDefaultLoaders(*loaders);
357 _runResources->setTagLoaders(loaders);
359 std::auto_ptr<NamingPolicy> np(new IncrementalRename(_baseurl));
360 boost::shared_ptr<StreamProvider> sp(new StreamProvider(np));
362 _runResources->setStreamProvider(sp);
364 // Set the Hardware video decoding resources. none, vaapi, xv, omap
365 _runResources->setHWAccelBackend(_hwaccel);
366 // Set the Renderer resource, opengl, agg, or cairo
367 _runResources->setRenderBackend(_renderer);
369 printf("FIXME: %d\n", __LINE__);
371 init_gui();
373 // Initialize gui (we need argc/argv for this)
374 // note that this will also initialize the renderer
375 // which is *required* during movie loading
376 if (!_gui->init(argc, &argv)) {
377 std::cerr << "Could not initialize gui." << std::endl;
378 return EXIT_FAILURE;
381 // Parse querystring (before FlashVars, see
382 // testsuite/misc-ming.all/FlashVarsTest*)
383 setFlashVars(URL(_url).querystring());
385 // Add FlashVars.
386 Params::const_iterator fv = _params.find("flashvars");
387 if (fv != _params.end()) {
388 setFlashVars(fv->second);
391 // Add Scriptable Variables. These values beconme the default, but
392 // they can be reset from JavaScript via ExternalInterface. These
393 // are passed to Gnash using the '-P' option, and have nothing to
394 // to do with 'flashVars'.
395 fv = _params.begin();
396 for (fv=_params.begin(); fv != _params.end(); fv++) {
397 if (fv->first != "flashvars") {
398 setScriptableVar(fv->first, fv->second);
402 printf("FIXME: %d\n", __LINE__);
404 // Load the actual movie.
405 _movieDef = load_movie();
406 if (!_movieDef) {
407 return EXIT_FAILURE;
410 // Get info about the width & height of the movie.
411 int movie_width = static_cast<int>(_movieDef->get_width_pixels());
412 int movie_height = static_cast<int>(_movieDef->get_height_pixels());
414 if (! _width) {
415 _width = static_cast<size_t>(movie_width * _scale);
417 if (! _height) {
418 _height = static_cast<size_t>(movie_height * _scale);
421 if (! _width || ! _height) {
422 log_debug(_("Input movie has collapsed dimensions "
423 "%d/%d. Setting to 1/1 and going on."),
424 _width, _height);
425 if (!_width) _width = 1;
426 if (!_height) _height = 1;
429 // Register movie definition before creating the window
430 _gui->setMovieDefinition(_movieDef.get());
432 // Now that we know about movie size, create gui window.
433 _gui->createWindow(_url.c_str(), _width, _height, _xPosition, _yPosition);
435 movie_root root(*_movieDef, _gui->getClock(), *_runResources);
437 _callbacksHandler.reset(new CallbacksHandler(*_gui, *this));
439 // Register Player to receive events from the core (Mouse, Stage,
440 // System etc)
441 root.registerEventCallback(_callbacksHandler.get());
443 // Register Player to receive FsCommand events from the core.
444 root.registerFSCommandCallback(_callbacksHandler.get());
446 gnash::log_debug("Player Host FD #%d, Player Control FD #%d",
447 _hostfd, _controlfd);
449 // Set host requests fd (if any)
450 if ( _hostfd != -1 ) {
451 root.setHostFD(_hostfd);
454 if (_controlfd != -1) {
455 root.setControlFD(_controlfd);
456 _gui->setFDCallback(_controlfd, boost::bind(&Gui::quit, boost::ref(_gui)));
459 _gui->setStage(&root);
461 // When startStopped is true, stop here after the stage has been
462 // registered, but before the movie has started. Initial loading
463 // and VM initialization have been done by this stage, but not
464 // the complete parsing of the SWF. This is important because
465 // the Gui accesses movie_root to get the sound_handler, but also
466 // because the gui window should be properly set up by this point.
467 RcInitFile& rcfile = RcInitFile::getDefaultInstance();
469 if (rcfile.startStopped()) {
470 _gui->stop();
473 // Start loader thread
474 // NOTE: the loader thread might (in IMPORT tag parsing)
475 // create new movies and register them to the MovieLibrary.
476 // If MovieLibrary size exceeded, _movieDef might be
477 // destroyed prematurely. movie_root might actually be
478 // keeping it alive, as Gui might as well, but why relying
479 // on luck ? So we made sure to keep _movieDef by
480 // intrusive_ptr...
481 _movieDef->completeLoad();
483 if (! _delay) {
484 // 10ms per heart beat
485 _delay = 10;
487 _gui->setInterval(_delay);
489 if (_exitTimeout) {
490 _gui->setTimeout(static_cast<unsigned int>(_exitTimeout * 1000));
493 if (!_windowID && _startFullscreen) {
494 _gui->setFullscreen();
497 if (!_windowID && _hideMenu) {
498 _gui->hideMenu();
501 // Now handle stage alignment and scale mode. This should be done after
502 // the GUI is created, after its stage member is set, and after the
503 // interface callbacks are registered.
504 it = _params.find("salign");
505 if (it != _params.end()) {
506 log_debug("Setting align");
507 const short align = stringToStageAlign(it->second);
508 root.setStageAlignment(align);
511 it = _params.find("allowscriptaccess");
512 if (it != _params.end()) {
513 std::string access = it->second;
514 StringNoCaseEqual noCaseCompare;
515 const std::string& str = it->second;
517 movie_root::AllowScriptAccessMode mode = movie_root::sameDomain;
518 if (noCaseCompare(str, "never")) {
519 mode = movie_root::never;
520 } else if (noCaseCompare(str, "sameDomain")) {
521 mode = movie_root::sameDomain;
522 } else if (noCaseCompare(str, "always")) {
523 mode = movie_root::always;
525 log_debug("Setting allowscriptaccess to %s", mode);
526 root.setAllowScriptAccess(mode);
529 it = _params.find("scale");
530 if (it != _params.end()) {
531 StringNoCaseEqual noCaseCompare;
532 const std::string& str = it->second;
533 movie_root::ScaleMode mode = movie_root::showAll;
535 if (noCaseCompare(str, "noScale")) {
536 mode = movie_root::noScale;
537 } else if (noCaseCompare(str, "exactFit")) {
538 mode = movie_root::exactFit;
539 } else if (noCaseCompare(str, "noBorder")) {
540 mode = movie_root::noBorder;
543 log_debug("Setting scale mode");
544 root.setStageScaleMode(mode);
547 // Set up screenshots.
548 if (!_screenshots.empty()) {
549 std::istringstream is(_screenshots);
550 std::string arg;
551 bool last = false;
552 ScreenShotter::FrameList v;
554 while (std::getline(is, arg, ',')) {
555 if (arg == "last") last = true;
556 else try {
557 const size_t frame = boost::lexical_cast<size_t>(arg);
558 v.push_back(frame);
560 catch (boost::bad_lexical_cast&) {}
563 // Use default if filename is empty.
564 if (_screenshotFile.empty()) {
565 URL url(_runResources->baseURL());
566 std::string::size_type p = url.path().rfind('/');
567 const std::string& name = (p == std::string::npos) ? url.path() :
568 url.path().substr(p + 1);
569 _screenshotFile = "screenshot-" + name + "-%f";
572 _gui->requestScreenShots(v, last, _screenshotFile);
575 _gui->run();
577 log_debug("Main loop ended, cleaning up");
579 // Clean up as much as possible, so valgrind will help find actual leaks.
580 gnash::clear();
582 return EXIT_SUCCESS;
586 void
587 Player::CallbacksHandler::error(const std::string& msg)
589 _gui.error(msg);
592 bool
593 Player::CallbacksHandler::yesNo(const std::string& query)
595 return _gui.yesno(query);
598 std::string
599 Player::CallbacksHandler::call(const std::string& event, const std::string& arg)
601 StringNoCaseEqual noCaseCompare;
603 if (event == "Mouse.hide") {
604 return _gui.showMouse(false) ? "true" : "false";
607 if (event == "Mouse.show") {
608 return _gui.showMouse(true) ? "true" : "false";
611 if (event == "Stage.displayState") {
612 if (arg == "fullScreen") _gui.setFullscreen();
613 else if (arg == "normal") _gui.unsetFullscreen();
614 return "";
617 if (event == "Stage.scaleMode" || event == "Stage.align" ) {
618 _gui.updateStageMatrix();
619 return "";
622 if (event == "Stage.showMenu") {
623 if (noCaseCompare(arg, "true")) _gui.showMenu(true);
624 else if (noCaseCompare(arg, "false")) _gui.showMenu(false);
625 return "";
628 if (event == "Stage.resize") {
629 if ( _gui.isPlugin() ) {
630 log_debug("Player doing nothing on Stage.resize as we're a plugin");
631 return "";
634 // arg contains WIDTHxHEIGHT
635 log_debug("Player got Stage.resize(%s) message", arg);
636 int width, height;
637 sscanf(arg.c_str(), "%dx%d", &width, &height);
638 _gui.resizeWindow(width, height);
640 return "";
644 if (event == "System.capabilities.screenResolutionX") {
645 std::ostringstream ss;
646 ss << _gui.getScreenResX();
647 return ss.str();
650 if (event == "System.capabilities.screenResolutionY") {
651 std::ostringstream ss;
652 ss << _gui.getScreenResY();
653 return ss.str();
656 if (event == "System.capabilities.pixelAspectRatio") {
657 std::ostringstream ss;
658 // Whether the pp actively limits the precision or simply
659 // gets a slightly different result isn't clear.
660 ss << std::setprecision(7) << _gui.getPixelAspectRatio();
661 return ss.str();
664 if (event == "System.capabilities.screenDPI") {
665 std::ostringstream ss;
666 ss << _gui.getScreenDPI();
667 return ss.str();
670 if (event == "System.capabilities.screenColor") {
671 return _gui.getScreenColor();
674 if (event == "System.capabilities.playerType") {
675 return _gui.isPlugin() ? "PlugIn" : "StandAlone";
678 log_error(_("Unhandled callback %s with arguments %s"), event, arg);
679 return "";
682 void
683 Player::CallbacksHandler::notify(const std::string& command,
684 const std::string& args)
686 //log_debug(_("fs_callback(%p): %s %s"), (void*)movie, command, args);
688 gnash::RcInitFile& rcfile = gnash::RcInitFile::getDefaultInstance();
690 // it's _hostfd, but we're a static method...
691 const int hostfd = _player.getHostFD();
692 if (hostfd != -1) {
693 //log_debug("user-provided host requests fd is %d", hostfd);
694 std::stringstream request;
695 request << "INVOKE " << command << ":" << args << std::endl;
697 std::string requestString = request.str();
698 const char* cmd = requestString.c_str();
699 size_t len = requestString.length();
700 // TODO: should mutex-protect this ?
701 // NOTE: we assuming the hostfd is set in blocking mode here..
702 //log_debug("Attempt to write INVOKE requests fd %d", hostfd);
703 int ret = write(hostfd, cmd, len);
704 if ( ret == -1 ) {
705 log_error("Could not write to user-provided host "
706 "requests fd %d: %s", hostfd, strerror(errno));
708 if ( static_cast<size_t>(ret) < len ) {
709 log_error("Could only write %d bytes over %d required to "
710 "user-provided host requests fd %d",
711 ret, len, hostfd);
714 // Remove the newline for logging
715 requestString.resize(requestString.size() - 1);
716 log_debug(_("Sent FsCommand '%s' to host fd %d"),
717 requestString, hostfd);
720 /// Fscommands can be ignored using an rcfile setting. As a
721 /// plugin they are always ignored.
722 if (_gui.isPlugin()) {
723 // We log the request to the fd above
724 log_debug(_("Running as plugin: skipping internal "
725 "handling of FsCommand %s%s."));
726 return;
729 // This only disables fscommands for the standalone player. In the
730 // plugin or a hosting application, the fscommands are always passed
731 // on; the hosting application should decide what to do with them.
732 // (Or do we want to allow disabling all external communication?)
733 if (rcfile.ignoreFSCommand()) return;
735 StringNoCaseEqual noCaseCompare;
737 // There are six defined FsCommands handled by the standalone player:
738 // quit, fullscreen, showmenu, exec, allowscale, and trapallkeys.
740 // FSCommand quit
741 if (noCaseCompare(command, "quit")) {
742 _gui.quit();
743 return;
746 // FSCommand fullscreen
747 if (noCaseCompare(command, "fullscreen")) {
748 if (noCaseCompare(args, "true")) _gui.setFullscreen();
749 else if (noCaseCompare(args, "false")) _gui.unsetFullscreen();
750 return;
753 // FSCommand showmenu
754 if (noCaseCompare(command, "showmenu")) {
755 if (noCaseCompare(args, "true")) _gui.showMenu(true);
756 else if (noCaseCompare(args, "false")) _gui.showMenu(false);
757 return;
760 // FSCommand exec
761 // Note: the pp insists that the file to execute should be in
762 // a subdirectory 'fscommand' of the 'projector' executable's
763 // location. In SWF5 there were no restrictions.
764 if (noCaseCompare(command, "exec")) {
765 log_unimpl(_("FsCommand exec called with argument %s"), args);
766 return;
769 // FSCommand allowscale
770 if (noCaseCompare(command, "allowscale")) {
771 //log_debug("allowscale: %s", args);
772 if (noCaseCompare(args, "true")) _gui.allowScale(true);
773 else {
774 if (strtol(args.c_str(), NULL, 0)) _gui.allowScale(true);
775 else _gui.allowScale(false);
777 return;
780 // FSCommand trapallkeys
781 if (noCaseCompare(command, "trapallkeys")) {
782 log_unimpl(_("FsCommand trapallkeys called with argument %s"), args);
783 return;
786 // The plugin never reaches this point; anything sent to the fd has
787 // been logged already.
788 log_debug(_("FsCommand '%s(%s)' not handled internally"),
789 command, args);
794 // private
795 std::auto_ptr<Gui>
796 Player::getGui()
798 #ifdef GUI_GTK
799 return createGTKGui(_windowID, _scale, _doLoop, *_runResources);
800 #endif
802 #ifdef GUI_KDE3
803 return createKDEGui(_windowID, _scale, _doLoop, *_runResources);
804 #endif
806 #ifdef GUI_KDE4
807 return createKDE4Gui(_windowID, _scale, _doLoop, *_runResources);
808 #endif
810 #ifdef GUI_SDL
811 return createSDLGui(_windowID, _scale, _doLoop, *_runResources);
812 #endif
814 #ifdef GUI_AQUA
815 return createAQUAGui(_windowID, _scale, _doLoop, *_runResources);
816 #endif
818 #ifdef GUI_RISCOS
819 return createRISCOSGui(_windowID, _scale, _doLoop, *_runResources);
820 #endif
822 #ifdef GUI_FLTK
823 return createFLTKGui(_windowID, _scale, _doLoop, *_runResources);
824 #endif
826 #ifdef GUI_FB
827 return createFBGui(_windowID, _scale, _doLoop, *_runResources);
828 #endif
830 #ifdef GUI_AOS4
831 return createAOS4Gui(_windowID, _scale, _doLoop, *_runResources);
832 #endif
834 #ifdef GUI_HAIKU
835 return createHaikuGui(_windowID, _scale, _doLoop, *_runResources);
836 #endif
838 #ifdef GUI_DUMP
839 return createDumpGui(_windowID, _scale, _doLoop, *_runResources);
840 #endif
842 return std::auto_ptr<Gui>(new NullGui(_doLoop, *_runResources));
845 Player::~Player()
847 if (_movieDef.get()) {
848 log_debug("~Player - _movieDef refcount: %d (1 will be dropped "
849 "now)", _movieDef->get_ref_count());