big merge from master, fix rpm creation, drop fetching swfdec
[gnash.git] / gui / Player.cpp
blob1ec707b5f8df959eab04197bdbcc2fe1bdcbb795
1 // Player.cpp: Top level SWF player, for gnash.
2 //
3 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010,
4 // 2011 Free Software 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 #include "Player.h"
27 #include <iostream>
28 #include <sstream>
29 #include <boost/lexical_cast.hpp>
30 #include <boost/variant/static_visitor.hpp>
31 #include <boost/any.hpp>
32 #include <utility>
33 #include <memory>
34 #include <vector>
36 #include "gui.h"
37 #include "NullGui.h"
38 #include "MovieFactory.h"
39 #include "movie_definition.h"
40 #include "sound_handler.h" // for set_sound_handler and create_sound_handler_*
41 #include "MovieClip.h" // for setting FlashVars
42 #include "movie_root.h"
43 #include "StreamProvider.h"
44 #include "swf/TagLoadersTable.h"
45 #include "swf/DefaultTagLoaders.h"
46 #include "NamingPolicy.h"
47 #include "StringPredicates.h"
48 #include "URL.h"
49 #include "rc.h"
50 #include "GnashException.h"
51 #include "noseek_fd_adapter.h"
52 #include "VM.h"
53 #include "SystemClock.h"
54 #include "ExternalInterface.h"
55 #include "ScreenShotter.h"
56 #include "GnashSystemIOHeaders.h" // for write()
57 #include "log.h"
58 #include "HostInterface.h"
60 using namespace gnash;
62 namespace {
63 gnash::LogFile& dbglogfile = gnash::LogFile::getDefaultInstance();
66 namespace {
68 class MessageHandler : public boost::static_visitor<boost::any>
70 public:
71 explicit MessageHandler(Gui& g) : _gui(g) {}
73 boost::any operator()(const HostMessage& e) {
75 switch (e.event()) {
77 case HostMessage::NOTIFY_ERROR:
78 _gui.error(boost::any_cast<std::string>(e.arg()));
79 return boost::blank();
81 case HostMessage::QUERY:
82 return _gui.yesno(boost::any_cast<std::string>(e.arg()));
84 case HostMessage::SHOW_MOUSE:
86 // Must return a bool, true if the mouse was visible before.
87 return _gui.showMouse(boost::any_cast<bool>(e.arg()));
90 case HostMessage::SET_DISPLAYSTATE:
92 const movie_root::DisplayState s =
93 boost::any_cast<movie_root::DisplayState>(e.arg());
94 if (s == movie_root::DISPLAYSTATE_FULLSCREEN) {
95 _gui.setFullscreen();
97 else if (s == movie_root::DISPLAYSTATE_NORMAL) {
98 _gui.unsetFullscreen();
100 return boost::blank();
103 case HostMessage::UPDATE_STAGE:
104 _gui.updateStageMatrix();
105 return boost::blank();
107 case HostMessage::SHOW_MENU:
108 _gui.showMenu(boost::any_cast<bool>(e.arg()));
109 return boost::blank();
111 case HostMessage::SET_CLIPBOARD:
112 _gui.setClipboard(boost::any_cast<std::string>(e.arg()));
113 return boost::blank();
115 case HostMessage::RESIZE_STAGE:
117 if (_gui.isPlugin()) {
118 log_debug("Player doing nothing on Stage.resize as we're a plugin");
119 return boost::blank();
122 typedef std::pair<int, int> Dimensions;
123 const Dimensions i = boost::any_cast<Dimensions>(e.arg());
124 _gui.resizeWindow(i.first, i.second);
125 return boost::blank();
127 case HostMessage::EXTERNALINTERFACE_ISPLAYING:
128 return (_gui.isStopped()) ? false : true;
130 case HostMessage::EXTERNALINTERFACE_PAN:
131 log_unimpl("GUI ExternalInterface.Pan event");
132 return boost::blank();
134 case HostMessage::EXTERNALINTERFACE_PLAY:
135 _gui.play();
136 return boost::blank();
138 case HostMessage::EXTERNALINTERFACE_REWIND:
139 _gui.restart();
140 return boost::blank();
142 case HostMessage::EXTERNALINTERFACE_SETZOOMRECT:
143 log_unimpl("GUI ExternalInterface.SetZoomRect event");
144 return boost::blank();
146 case HostMessage::EXTERNALINTERFACE_STOPPLAY:
147 _gui.pause();
148 return boost::blank();
150 case HostMessage::EXTERNALINTERFACE_ZOOM:
151 log_unimpl("GUI ExternalInterface.Zoom event");
152 return boost::blank();
154 case HostMessage::SCREEN_RESOLUTION:
155 return _gui.screenResolution();
157 case HostMessage::SCREEN_DPI:
158 return _gui.getScreenDPI();
160 case HostMessage::SCREEN_COLOR:
161 return _gui.getScreenColor();
163 case HostMessage::PIXEL_ASPECT_RATIO:
164 return _gui.getPixelAspectRatio();
166 case HostMessage::PLAYER_TYPE:
167 return std::string(_gui.isPlugin() ? "PlugIn" : "StandAlone");
169 log_error(_("Unhandled callback %s with arguments %s"), +e.event());
170 return boost::blank();
173 boost::any operator()(const CustomMessage& /*e*/) {
174 return boost::blank();
176 private:
177 Gui& _gui;
182 void
183 Player::setFlashVars(const std::string& varstr)
185 typedef Gui::VariableMap maptype;
187 maptype vars;
188 URL::parse_querystring(varstr, vars);
190 _gui->addFlashVars(vars);
193 Player::Player()
195 #if defined(RENDERER_CAIRO)
196 _bitDepth(32),
197 #else
198 _bitDepth(16),
199 #endif
200 _scale(1.0f),
201 _delay(0),
202 _width(0),
203 _height(0),
204 _xPosition(-1),
205 _yPosition(-1),
206 _windowID(0),
207 _doLoop(true),
208 _doRender(true),
209 _doSound(true),
210 _exitTimeout(0),
211 _movieDef(0),
212 _maxAdvances(0),
213 #ifdef GNASH_FPS_DEBUG
214 _fpsDebugTime(0.0),
215 #endif
216 _hostfd(-1),
217 _controlfd(-1),
218 _startFullscreen(false),
219 _hideMenu(false),
220 _screenshotQuality(100)
224 float
225 Player::setScale(float newscale)
227 float oldscale = _scale;
228 _scale = newscale;
229 return oldscale;
232 void
233 Player::init_logfile()
235 dbglogfile.setWriteDisk(false);
237 RcInitFile& rcfile = RcInitFile::getDefaultInstance();
238 if (rcfile.useWriteLog()) {
239 dbglogfile.setWriteDisk(true);
242 dbglogfile.setLogFilename(rcfile.getDebugLog());
244 if (rcfile.verbosityLevel() > 0) {
245 dbglogfile.setVerbosity(rcfile.verbosityLevel());
248 if (rcfile.useActionDump()) {
249 dbglogfile.setActionDump(true);
250 dbglogfile.setVerbosity();
253 if (rcfile.useParserDump()) {
254 dbglogfile.setParserDump(true);
255 dbglogfile.setVerbosity();
258 // If a delay was not specified yet use
259 // any eventual setting for it found in
260 // the RcInitFile
262 // TODO: we should remove all uses of the rcfile
263 // from Player class..
265 if (!_delay && rcfile.getTimerDelay() > 0) {
266 _delay = rcfile.getTimerDelay();
267 log_debug (_("Timer delay set to %d milliseconds"), _delay);
272 void
273 Player::init_sound()
276 if (_doSound) {
277 try {
278 #ifdef SOUND_SDL
279 _soundHandler.reset(sound::create_sound_handler_sdl(
280 _mediaHandler.get()));
281 #elif defined(SOUND_AHI)
282 _soundHandler.reset(sound::create_sound_handler_aos4(
283 _mediaHandler.get()));
284 #elif defined(SOUND_MKIT)
285 _soundHandler.reset(sound::create_sound_handler_mkit(
286 _mediaHandler.get()));
287 #else
288 log_error(_("Sound requested but no sound support compiled in"));
289 return;
290 #endif
292 } catch (const SoundException& ex) {
293 log_error(_("Could not create sound handler: %s."
294 " Will continue w/out sound."), ex.what());
299 void
300 Player::init_gui()
302 if (_doRender) {
303 _gui = getGui();
304 } else {
305 _gui.reset(new NullGui(_doLoop, *_runResources));
308 _gui->setAudioDump(_audioDump);
309 _gui->setMaxAdvances(_maxAdvances);
311 #ifdef GNASH_FPS_DEBUG
312 if (_fpsDebugTime) {
313 log_debug(_("Activating FPS debugging every %g seconds"),
314 _fpsDebugTime);
315 _gui->setFpsTimerInterval(_fpsDebugTime);
317 #endif
320 boost::intrusive_ptr<movie_definition>
321 Player::load_movie()
323 /// The RunResources must be initialized by this point to provide resources
324 /// for parsing.
325 assert(_runResources.get());
327 boost::intrusive_ptr<gnash::movie_definition> md;
329 RcInitFile& rcfile = RcInitFile::getDefaultInstance();
330 URL vurl(_url);
332 if (vurl.protocol() == "file") {
333 const std::string& path = vurl.path();
334 size_t lastSlash = path.find_last_of('/');
335 std::string dir = path.substr(0, lastSlash+1);
336 rcfile.addLocalSandboxPath(dir);
337 log_debug(_("%s appended to local sandboxes"), dir.c_str());
340 try {
341 if (_infile == "-") {
342 std::auto_ptr<IOChannel> in (
343 noseek_fd_adapter::make_stream(fileno(stdin)));
344 md = MovieFactory::makeMovie(in, _url, *_runResources, false);
346 else {
347 URL url(_infile);
348 if ( url.protocol() == "file" ) {
349 std::string path = url.path();
350 // We'll need to allow load of the file, no matter virtual url
351 // specified...
352 // This is kind of hackish, cleaner would be adding an argument
353 // to createMovie to skip the security checking phase.
354 // NOTE that if we fail to allow this load, the konqueror plugin
355 // would not be able to load anything
357 rcfile.addLocalSandboxPath(path);
358 log_debug(_("%s appended to local sandboxes"), path.c_str());
361 // _url should be always set at this point...
362 md = MovieFactory::makeMovie(url, *_runResources, _url.c_str(),
363 false);
366 catch (const GnashException& er) {
367 std::cerr << er.what() << std::endl;
368 md = NULL;
371 if (!md) {
372 fprintf(stderr, "Could not load movie '%s'\n", _infile.c_str());
373 return NULL;
376 return md;
379 /// \brief Run, used to open a new flash file. Using previous initialization
380 void
381 Player::run(int argc, char* argv[], const std::string& infile,
382 const std::string& url)
384 // Call this at run() time, so the caller has
385 // a cache of setting some parameter before calling us...
386 // (example: setDoSound(), setWindowId() etc.. )
387 init_logfile();
389 // gnash.cpp should check that a filename is supplied.
390 assert (!infile.empty());
392 _infile = infile;
394 // Work out base url
395 if (_baseurl.empty()) {
396 if (!url.empty()) _baseurl = url;
397 else if (infile == "-") _baseurl = URL("./").str();
398 else _baseurl = infile;
401 // Set _root._url (either explicit of from infile)
402 if (!url.empty()) {
403 _url = url;
404 } else {
405 _url = infile;
408 // Parse player parameters. These are not passed to the SWF, but rather
409 // control stage properties etc.
410 // NOTE: it is intentional to force a trailing slash to "base" argument
411 // as it was tested that the "base" argument is always considered
412 // a directory!
413 Params::const_iterator it = _params.find("base");
414 const URL baseURL = (it == _params.end()) ? _baseurl :
415 URL(it->second+"/", _baseurl);
416 /// The RunResources should be populated before parsing.
417 _runResources.reset(new RunResources());
419 boost::shared_ptr<SWF::TagLoadersTable> loaders(new SWF::TagLoadersTable());
420 addDefaultLoaders(*loaders);
421 _runResources->setTagLoaders(loaders);
423 std::auto_ptr<NamingPolicy> np(new IncrementalRename(_baseurl));
425 /// The StreamProvider uses the actual URL of the loaded movie.
426 boost::shared_ptr<StreamProvider> sp(new StreamProvider(_url, baseURL, np));
428 _runResources->setStreamProvider(sp);
430 // Set the Hardware video decoding resources. none, vaapi, omap
431 _runResources->setHWAccelBackend(_hwaccel);
432 // Set the Renderer resource, opengl, agg, or cairo
433 _runResources->setRenderBackend(_renderer);
435 _mediaHandler.reset(media::MediaFactory::instance().get(_media));
437 if (!_mediaHandler.get()) {
438 boost::format fmt =
439 boost::format(_("Non-existent media handler %1% specified"))
440 % _media;
441 throw GnashException(fmt.str());
444 _runResources->setMediaHandler(_mediaHandler);
446 init_sound();
447 _runResources->setSoundHandler(_soundHandler);
449 init_gui();
451 // Initialize gui (we need argc/argv for this)
452 // note that this will also initialize the renderer
453 // which is *required* during movie loading
454 if (!_gui->init(argc, &argv)) {
455 throw GnashException("Could not initialize GUI");
458 // Parse querystring (before FlashVars, see
459 // testsuite/misc-ming.all/FlashVarsTest*)
460 setFlashVars(URL(_url).querystring());
462 // Add FlashVars.
463 Params::const_iterator fv = _params.find("flashvars");
464 if (fv != _params.end()) {
465 setFlashVars(fv->second);
468 // Load the actual movie.
469 _movieDef = load_movie();
470 if (!_movieDef) {
471 throw GnashException("Could not load movie!");
474 // Get info about the width & height of the movie.
475 const size_t movie_width = _movieDef->get_width_pixels();
476 const size_t movie_height = _movieDef->get_height_pixels();
478 if (! _width) {
479 _width = static_cast<size_t>(movie_width * _scale);
481 if (! _height) {
482 _height = static_cast<size_t>(movie_height * _scale);
485 if (!_width || !_height) {
486 log_debug(_("Input movie has collapsed dimensions "
487 "%d/%d. Setting to 1/1 and going on."),
488 _width, _height);
489 if (!_width) _width = 1;
490 if (!_height) _height = 1;
493 // Register movie definition before creating the window
494 _gui->setMovieDefinition(_movieDef.get());
496 // Now that we know about movie size, create gui window.
497 _gui->createWindow(_url.c_str(), _width, _height, _xPosition, _yPosition);
499 movie_root root(*_movieDef, _gui->getClock(), *_runResources);
501 _callbacksHandler.reset(new CallbacksHandler(*_gui, *this));
503 // Register Player to receive events from the core (Mouse, Stage,
504 // System etc)
505 root.registerEventCallback(_callbacksHandler.get());
507 // Register Player to receive FsCommand events from the core.
508 root.registerFSCommandCallback(_callbacksHandler.get());
510 log_debug("Player Host FD #%d, Player Control FD #%d",
511 _hostfd, _controlfd);
513 // Set host requests fd (if any)
514 if ( _hostfd != -1 ) {
515 root.setHostFD(_hostfd);
518 if (_controlfd != -1) {
519 root.setControlFD(_controlfd);
522 _gui->setStage(&root);
524 // When startStopped is true, stop here after the stage has been
525 // registered, but before the movie has started. Initial loading
526 // and VM initialization have been done by this stage, but not
527 // the complete parsing of the SWF. This is important because
528 // the Gui accesses movie_root to get the sound_handler, but also
529 // because the gui window should be properly set up by this point.
530 RcInitFile& rcfile = RcInitFile::getDefaultInstance();
532 if (rcfile.startStopped()) {
533 _gui->stop();
536 // Start loader thread
537 // NOTE: the loader thread might (in IMPORT tag parsing)
538 // create new movies and register them to the MovieLibrary.
539 // If MovieLibrary size exceeded, _movieDef might be
540 // destroyed prematurely. movie_root might actually be
541 // keeping it alive, as Gui might as well, but why relying
542 // on luck ? So we made sure to keep _movieDef by
543 // intrusive_ptr...
544 _movieDef->completeLoad();
546 if (! _delay) {
547 // 10ms per heart beat
548 _delay = 10;
550 _gui->setInterval(_delay);
552 if (_exitTimeout) {
553 _gui->setTimeout(static_cast<unsigned int>(_exitTimeout * 1000));
556 if (!_windowID && _startFullscreen) {
557 _gui->setFullscreen();
560 if (!_windowID && _hideMenu) {
561 _gui->hideMenu();
564 // Now handle stage alignment and scale mode. This should be done after
565 // the GUI is created, after its stage member is set, and after the
566 // interface callbacks are registered.
567 it = _params.find("salign");
568 if (it != _params.end()) {
569 log_debug("Setting align");
570 const short align = stringToStageAlign(it->second);
571 root.setStageAlignment(align);
574 it = _params.find("allowscriptaccess");
575 if (it != _params.end()) {
576 std::string access = it->second;
577 StringNoCaseEqual noCaseCompare;
578 const std::string& str = it->second;
580 movie_root::AllowScriptAccessMode mode =
581 movie_root::SCRIPT_ACCESS_SAME_DOMAIN;
583 if (noCaseCompare(str, "never")) {
584 mode = movie_root::SCRIPT_ACCESS_NEVER;
586 else if (noCaseCompare(str, "sameDomain")) {
587 mode = movie_root::SCRIPT_ACCESS_SAME_DOMAIN;
589 else if (noCaseCompare(str, "always")) {
590 mode = movie_root::SCRIPT_ACCESS_ALWAYS;
592 log_debug("Setting allowscriptaccess to %s", mode);
593 root.setAllowScriptAccess(mode);
596 it = _params.find("scale");
597 if (it != _params.end()) {
598 StringNoCaseEqual noCaseCompare;
599 const std::string& str = it->second;
600 movie_root::ScaleMode mode = movie_root::SCALEMODE_SHOWALL;
602 if (noCaseCompare(str, "noScale")) {
603 mode = movie_root::SCALEMODE_NOSCALE;
605 else if (noCaseCompare(str, "exactFit")) {
606 mode = movie_root::SCALEMODE_EXACTFIT;
608 else if (noCaseCompare(str, "noBorder")) {
609 mode = movie_root::SCALEMODE_NOBORDER;
612 log_debug("Setting scale mode");
613 root.setStageScaleMode(mode);
616 // Set up screenshots.
617 if (!_screenshots.empty()) {
618 std::istringstream is(_screenshots);
619 std::string arg;
620 bool last = false;
621 ScreenShotter::FrameList v;
623 while (std::getline(is, arg, ',')) {
624 if (arg == "last") last = true;
625 else try {
626 const size_t frame = boost::lexical_cast<size_t>(arg);
627 v.push_back(frame);
629 catch (const boost::bad_lexical_cast&) {}
632 // Use default if filename is empty.
633 if (_screenshotFile.empty()) {
634 URL url(_runResources->streamProvider().baseURL());
635 std::string::size_type p = url.path().rfind('/');
636 const std::string& name = (p == std::string::npos) ? url.path() :
637 url.path().substr(p + 1);
638 _screenshotFile = "screenshot-" + name + "-%f";
640 if (!last && v.empty()) return;
642 std::auto_ptr<ScreenShotter> ss(new ScreenShotter(_screenshotFile, _screenshotQuality));
643 if (last) ss->lastFrame();
644 ss->setFrames(v);
645 _gui->setScreenShotter(ss);
648 _gui->run();
650 log_debug("Main loop ended, cleaning up");
652 // Clean up as much as possible, so valgrind will help find actual leaks.
653 MovieFactory::clear();
657 void
658 Player::CallbacksHandler::exit()
660 _gui.quit();
663 boost::any
664 Player::CallbacksHandler::call(const HostInterface::Message& e)
666 MessageHandler v(_gui);
667 try {
668 return boost::apply_visitor(v, e);
670 catch (const boost::bad_any_cast&) {
671 log_error(_("Got unexpected argument type for message %1%"), e);
672 return boost::blank();
676 void
677 Player::CallbacksHandler::notify(const std::string& command,
678 const std::string& args)
680 //log_debug(_("fs_callback(%p): %s %s"), (void*)movie, command, args);
682 gnash::RcInitFile& rcfile = gnash::RcInitFile::getDefaultInstance();
684 // it's _hostfd, but we're a static method...
685 const int hostfd = _player.getHostFD();
686 if (hostfd != -1) {
687 //log_debug("user-provided host requests fd is %d", hostfd);
688 std::stringstream request;
689 std::vector<as_value> fnargs;
690 fnargs.push_back(as_value(command));
691 fnargs.push_back(as_value(args));
692 request << ExternalInterface::makeInvoke("fsCommand", fnargs);
694 std::string requestString = request.str();
695 const char* cmd = requestString.c_str();
696 size_t len = requestString.length();
697 // TODO: should mutex-protect this ?
698 // NOTE: we assuming the hostfd is set in blocking mode here..
699 //log_debug("Attempt to write INVOKE requests fd %d", hostfd);
700 int ret = write(hostfd, cmd, len);
701 if ( ret == -1 ) {
702 log_error("Could not write to user-provided host "
703 "requests fd %d: %s", hostfd, strerror(errno));
705 if ( static_cast<size_t>(ret) < len ) {
706 log_error("Could only write %d bytes over %d required to "
707 "user-provided host requests fd %d",
708 ret, len, hostfd);
711 // Remove the newline for logging
712 requestString.resize(requestString.size() - 1);
713 log_debug(_("Sent FsCommand '%s' to host fd %d"),
714 requestString, hostfd);
717 /// Fscommands can be ignored using an rcfile setting. As a
718 /// plugin they are always ignored.
719 if (_gui.isPlugin()) {
720 // We log the request to the fd above
721 log_debug(_("Running as plugin: skipping internal "
722 "handling of FsCommand %s%s."));
723 return;
726 // This only disables fscommands for the standalone player. In the
727 // plugin or a hosting application, the fscommands are always passed
728 // on; the hosting application should decide what to do with them.
729 // (Or do we want to allow disabling all external communication?)
730 if (rcfile.ignoreFSCommand()) return;
732 StringNoCaseEqual noCaseCompare;
734 // There are six defined FsCommands handled by the standalone player:
735 // quit, fullscreen, showmenu, exec, allowscale, and trapallkeys.
737 // FSCommand quit
738 if (noCaseCompare(command, "quit")) {
739 _gui.quit();
740 return;
743 // FSCommand fullscreen
744 if (noCaseCompare(command, "fullscreen")) {
745 if (noCaseCompare(args, "true")) _gui.setFullscreen();
746 else if (noCaseCompare(args, "false")) _gui.unsetFullscreen();
747 return;
750 // FSCommand showmenu
751 if (noCaseCompare(command, "showmenu")) {
752 if (noCaseCompare(args, "true")) _gui.showMenu(true);
753 else if (noCaseCompare(args, "false")) _gui.showMenu(false);
754 return;
757 // FSCommand exec
758 // Note: the pp insists that the file to execute should be in
759 // a subdirectory 'fscommand' of the 'projector' executable's
760 // location. In SWF5 there were no restrictions.
761 if (noCaseCompare(command, "exec")) {
762 log_unimpl(_("FsCommand exec called with argument %s"), args);
763 return;
766 // FSCommand allowscale
767 if (noCaseCompare(command, "allowscale")) {
768 //log_debug("allowscale: %s", args);
769 if (noCaseCompare(args, "true")) _gui.allowScale(true);
770 else {
771 if (strtol(args.c_str(), NULL, 0)) _gui.allowScale(true);
772 else _gui.allowScale(false);
774 return;
777 // FSCommand trapallkeys
778 if (noCaseCompare(command, "trapallkeys")) {
779 log_unimpl(_("FsCommand trapallkeys called with argument %s"), args);
780 return;
783 // The plugin never reaches this point; anything sent to the fd has
784 // been logged already.
785 log_debug(_("FsCommand '%s(%s)' not handled internally"),
786 command, args);
791 // private
792 std::auto_ptr<Gui>
793 Player::getGui()
795 #ifdef GUI_GTK
796 return createGTKGui(_windowID, _scale, _doLoop, *_runResources);
797 #endif
799 #ifdef GUI_KDE3
800 return createKDEGui(_windowID, _scale, _doLoop, *_runResources);
801 #endif
803 #ifdef GUI_KDE4
804 return createKDE4Gui(_windowID, _scale, _doLoop, *_runResources);
805 #endif
807 #ifdef GUI_SDL
808 return createSDLGui(_windowID, _scale, _doLoop, *_runResources);
809 #endif
811 #ifdef GUI_AQUA
812 return createAQUAGui(_windowID, _scale, _doLoop, *_runResources);
813 #endif
815 #ifdef GUI_RISCOS
816 return createRISCOSGui(_windowID, _scale, _doLoop, *_runResources);
817 #endif
819 #ifdef GUI_FLTK
820 return createFLTKGui(_windowID, _scale, _doLoop, *_runResources);
821 #endif
823 #ifdef GUI_FB
824 return createFBGui(_windowID, _scale, _doLoop, *_runResources);
825 #endif
827 #ifdef GUI_AOS4
828 return createAOS4Gui(_windowID, _scale, _doLoop, *_runResources);
829 #endif
831 #ifdef GUI_HAIKU
832 return createHaikuGui(_windowID, _scale, _doLoop, *_runResources);
833 #endif
835 #ifdef GUI_DUMP
836 return createDumpGui(_windowID, _scale, _doLoop, *_runResources);
837 #endif
839 return std::auto_ptr<Gui>(new NullGui(_doLoop, *_runResources));
842 Player::~Player()
844 if (_movieDef.get()) {
845 log_debug("~Player - _movieDef refcount: %d (1 will be dropped "
846 "now)", _movieDef->get_ref_count());