Drop the bool operator for ObjectURI, to avoid getting the kind of side-effect that...
[gnash.git] / gui / Player.cpp
blobc34043f568ac640ed1287a92622932fc9b8b69c9
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"
50 #include "ExternalInterface.h"
52 #include "GnashSystemIOHeaders.h" // for write()
53 #include "log.h"
54 #include <iostream>
55 #include <sstream>
56 #include <iomanip>
57 #include <boost/lexical_cast.hpp>
59 using namespace gnash;
61 namespace {
62 gnash::LogFile& dbglogfile = gnash::LogFile::getDefaultInstance();
65 void
66 Player::setFlashVars(const std::string& varstr)
68 typedef Gui::VariableMap maptype;
70 maptype vars;
71 URL::parse_querystring(varstr, vars);
73 _gui->addFlashVars(vars);
76 void
77 Player::setScriptableVar(const std::string &name, const std::string &value)
79 _gui->addScriptableVar(name, value);
82 Player::Player()
84 #if defined(RENDERER_CAIRO)
85 _bitDepth(32),
86 #else
87 _bitDepth(16),
88 #endif
89 _scale(1.0f),
90 _delay(0),
91 _width(0),
92 _height(0),
93 _xPosition(-1),
94 _yPosition(-1),
95 _windowID(0),
96 _doLoop(true),
97 _doRender(true),
98 _doSound(true),
99 _exitTimeout(0),
100 _movieDef(0),
101 _maxAdvances(0),
102 #ifdef GNASH_FPS_DEBUG
103 _fpsDebugTime(0.0),
104 #endif
105 _hostfd(-1),
106 _controlfd(-1),
107 _startFullscreen(false),
108 _hideMenu(false)
110 init();
113 float
114 Player::setScale(float newscale)
116 float oldscale = _scale;
117 _scale = newscale;
118 return oldscale;
121 void
122 Player::init()
124 /// Initialize gnash core library
125 gnashInit();
129 void
130 Player::init_logfile()
132 dbglogfile.setWriteDisk(false);
134 RcInitFile& rcfile = RcInitFile::getDefaultInstance();
135 if (rcfile.useWriteLog()) {
136 dbglogfile.setWriteDisk(true);
139 dbglogfile.setLogFilename(rcfile.getDebugLog());
141 if (rcfile.verbosityLevel() > 0) {
142 dbglogfile.setVerbosity(rcfile.verbosityLevel());
145 if (rcfile.useActionDump()) {
146 dbglogfile.setActionDump(true);
147 dbglogfile.setVerbosity();
150 if (rcfile.useParserDump()) {
151 dbglogfile.setParserDump(true);
152 dbglogfile.setVerbosity();
155 // If a delay was not specified yet use
156 // any eventual setting for it found in
157 // the RcInitFile
159 // TODO: we should remove all uses of the rcfile
160 // from Player class..
162 if (!_delay && rcfile.getTimerDelay() > 0) {
163 _delay = rcfile.getTimerDelay();
164 log_debug (_("Timer delay set to %d milliseconds"), _delay);
169 unsigned int
170 Player::silentStream(void* /*udata*/, boost::int16_t* stream, unsigned int len, bool& atEOF)
172 std::fill(stream, stream+len, 0);
173 atEOF=false;
174 return len;
177 void
178 Player::init_sound()
181 if (_doSound) {
182 try {
183 #ifdef SOUND_SDL
184 _soundHandler.reset(sound::create_sound_handler_sdl(
185 _mediaHandler.get(), _audioDump));
186 #elif defined(SOUND_AHI)
187 _soundHandler.reset(sound::create_sound_handler_aos4(
188 _mediaHandler.get(), _audioDump));
189 #elif defined(SOUND_MKIT)
190 _soundHandler.reset(sound::create_sound_handler_mkit(
191 _mediaHandler.get(), _audioDump));
192 #else
193 log_error(_("Sound requested but no sound support compiled in"));
194 return;
195 #endif
196 } catch (SoundException& ex) {
197 log_error(_("Could not create sound handler: %s."
198 " Will continue w/out sound."), ex.what());
200 if (! _audioDump.empty()) {
201 // add a silent stream to the audio pool so that our output file
202 // is homogenous; we actually want silent wave data when no sounds
203 // are playing on the stage
204 _soundHandler->attach_aux_streamer(silentStream, (void*) this);
209 void
210 Player::init_gui()
212 if (_doRender) {
213 _gui = getGui();
214 } else {
215 _gui.reset(new NullGui(_doLoop, *_runResources));
218 _gui->setMaxAdvances(_maxAdvances);
220 #ifdef GNASH_FPS_DEBUG
221 if (_fpsDebugTime) {
222 log_debug(_("Activating FPS debugging every %g seconds"),
223 _fpsDebugTime);
224 _gui->setFpsTimerInterval(_fpsDebugTime);
226 #endif
229 boost::intrusive_ptr<movie_definition>
230 Player::load_movie()
232 /// The RunResources must be initialized by this point to provide resources
233 /// for parsing.
234 assert(_runResources.get());
236 boost::intrusive_ptr<gnash::movie_definition> md;
238 RcInitFile& rcfile = RcInitFile::getDefaultInstance();
239 URL vurl(_url);
241 if (vurl.protocol() == "file") {
242 const std::string& path = vurl.path();
243 size_t lastSlash = path.find_last_of('/');
244 std::string dir = path.substr(0, lastSlash+1);
245 rcfile.addLocalSandboxPath(dir);
246 log_debug(_("%s appended to local sandboxes"), dir.c_str());
249 try {
250 if ( _infile == "-" ) {
251 std::auto_ptr<IOChannel> in (
252 noseek_fd_adapter::make_stream(fileno(stdin)));
253 md = MovieFactory::makeMovie(in, _url, *_runResources, false);
254 } else {
255 URL url(_infile);
256 if ( url.protocol() == "file" ) {
257 std::string path = url.path();
258 // We'll need to allow load of the file, no matter virtual url
259 // specified...
260 // This is kind of hackish, cleaner would be adding an argument
261 // to createMovie to skip the security checking phase.
262 // NOTE that if we fail to allow this load, the konqueror plugin
263 // would not be able to load anything
265 rcfile.addLocalSandboxPath(path);
266 log_debug(_("%s appended to local sandboxes"), path.c_str());
269 // _url should be always set at this point...
270 md = MovieFactory::makeMovie(url, *_runResources, _url.c_str(),
271 false);
273 } catch (const GnashException& er) {
274 std::cerr << er.what() << std::endl;
275 md = NULL;
278 if ( ! md ) {
279 fprintf(stderr, "Could not load movie '%s'\n", _infile.c_str());
280 return NULL;
283 return md;
286 /// \brief Run, used to open a new flash file. Using previous initialization
287 void
288 Player::run(int argc, char* argv[], const std::string& infile,
289 const std::string& url)
291 // Call this at run() time, so the caller has
292 // a cache of setting some parameter before calling us...
293 // (example: setDoSound(), setWindowId() etc.. )
294 init_logfile();
296 // gnash.cpp should check that a filename is supplied.
297 assert (!infile.empty());
299 _infile = infile;
301 // Work out base url
302 if (_baseurl.empty()) {
303 if (!url.empty()) _baseurl = url;
304 else if (infile == "-") _baseurl = URL("./").str();
305 else _baseurl = infile;
308 // Set _root._url (either explicit of from infile)
309 if (!url.empty()) {
310 _url = url;
311 } else {
312 _url = infile;
315 // Parse player parameters. These are not passed to the SWF, but rather
316 // control stage properties etc.
317 Params::const_iterator it = _params.find("base");
318 const URL baseURL = (it == _params.end()) ? _baseurl :
319 URL(it->second, _baseurl);
320 /// The RunResources should be populated before parsing.
321 _runResources.reset(new RunResources(baseURL.str()));
323 boost::shared_ptr<SWF::TagLoadersTable> loaders(new SWF::TagLoadersTable());
324 addDefaultLoaders(*loaders);
325 _runResources->setTagLoaders(loaders);
327 std::auto_ptr<NamingPolicy> np(new IncrementalRename(_baseurl));
328 boost::shared_ptr<StreamProvider> sp(new StreamProvider(np));
330 _runResources->setStreamProvider(sp);
332 // Set the Hardware video decoding resources. none, vaapi, xv, omap
333 _runResources->setHWAccelBackend(_hwaccel);
334 // Set the Renderer resource, opengl, agg, or cairo
335 _runResources->setRenderBackend(_renderer);
337 _mediaHandler.reset(media::MediaFactory::instance().get(_media));
339 if (!_mediaHandler.get()) {
340 boost::format fmt =
341 boost::format(_("Non-existent media handler %1% specified"))
342 % _media;
343 throw GnashException(fmt.str());
346 _runResources->setMediaHandler(_mediaHandler);
348 init_sound();
349 _runResources->setSoundHandler(_soundHandler);
351 init_gui();
353 // Initialize gui (we need argc/argv for this)
354 // note that this will also initialize the renderer
355 // which is *required* during movie loading
356 if (!_gui->init(argc, &argv)) {
357 throw GnashException("Could not initialize GUI");
360 // Parse querystring (before FlashVars, see
361 // testsuite/misc-ming.all/FlashVarsTest*)
362 setFlashVars(URL(_url).querystring());
364 // Add FlashVars.
365 Params::const_iterator fv = _params.find("flashvars");
366 if (fv != _params.end()) {
367 setFlashVars(fv->second);
370 // Load the actual movie.
371 _movieDef = load_movie();
372 if (!_movieDef) {
373 throw GnashException("Could not load movie!");
376 // Get info about the width & height of the movie.
377 const size_t movie_width = _movieDef->get_width_pixels();
378 const size_t movie_height = _movieDef->get_height_pixels();
380 if (! _width) {
381 _width = static_cast<size_t>(movie_width * _scale);
383 if (! _height) {
384 _height = static_cast<size_t>(movie_height * _scale);
387 if (!_width || !_height) {
388 log_debug(_("Input movie has collapsed dimensions "
389 "%d/%d. Setting to 1/1 and going on."),
390 _width, _height);
391 if (!_width) _width = 1;
392 if (!_height) _height = 1;
395 // Register movie definition before creating the window
396 _gui->setMovieDefinition(_movieDef.get());
398 // Now that we know about movie size, create gui window.
399 _gui->createWindow(_url.c_str(), _width, _height, _xPosition, _yPosition);
401 movie_root root(*_movieDef, _gui->getClock(), *_runResources);
403 _callbacksHandler.reset(new CallbacksHandler(*_gui, *this));
405 // Register Player to receive events from the core (Mouse, Stage,
406 // System etc)
407 root.registerEventCallback(_callbacksHandler.get());
409 // Register Player to receive FsCommand events from the core.
410 root.registerFSCommandCallback(_callbacksHandler.get());
412 log_debug("Player Host FD #%d, Player Control FD #%d",
413 _hostfd, _controlfd);
415 // Set host requests fd (if any)
416 if ( _hostfd != -1 ) {
417 root.setHostFD(_hostfd);
420 if (_controlfd != -1) {
421 root.setControlFD(_controlfd);
424 _gui->setStage(&root);
426 // When startStopped is true, stop here after the stage has been
427 // registered, but before the movie has started. Initial loading
428 // and VM initialization have been done by this stage, but not
429 // the complete parsing of the SWF. This is important because
430 // the Gui accesses movie_root to get the sound_handler, but also
431 // because the gui window should be properly set up by this point.
432 RcInitFile& rcfile = RcInitFile::getDefaultInstance();
434 if (rcfile.startStopped()) {
435 _gui->stop();
438 // Start loader thread
439 // NOTE: the loader thread might (in IMPORT tag parsing)
440 // create new movies and register them to the MovieLibrary.
441 // If MovieLibrary size exceeded, _movieDef might be
442 // destroyed prematurely. movie_root might actually be
443 // keeping it alive, as Gui might as well, but why relying
444 // on luck ? So we made sure to keep _movieDef by
445 // intrusive_ptr...
446 _movieDef->completeLoad();
448 if (! _delay) {
449 // 10ms per heart beat
450 _delay = 10;
452 _gui->setInterval(_delay);
454 if (_exitTimeout) {
455 _gui->setTimeout(static_cast<unsigned int>(_exitTimeout * 1000));
458 if (!_windowID && _startFullscreen) {
459 _gui->setFullscreen();
462 if (!_windowID && _hideMenu) {
463 _gui->hideMenu();
466 // Now handle stage alignment and scale mode. This should be done after
467 // the GUI is created, after its stage member is set, and after the
468 // interface callbacks are registered.
469 it = _params.find("salign");
470 if (it != _params.end()) {
471 log_debug("Setting align");
472 const short align = stringToStageAlign(it->second);
473 root.setStageAlignment(align);
476 it = _params.find("allowscriptaccess");
477 if (it != _params.end()) {
478 std::string access = it->second;
479 StringNoCaseEqual noCaseCompare;
480 const std::string& str = it->second;
482 movie_root::AllowScriptAccessMode mode =
483 movie_root::SCRIPT_ACCESS_SAME_DOMAIN;
485 if (noCaseCompare(str, "never")) {
486 mode = movie_root::SCRIPT_ACCESS_NEVER;
488 else if (noCaseCompare(str, "sameDomain")) {
489 mode = movie_root::SCRIPT_ACCESS_SAME_DOMAIN;
491 else if (noCaseCompare(str, "always")) {
492 mode = movie_root::SCRIPT_ACCESS_ALWAYS;
494 log_debug("Setting allowscriptaccess to %s", mode);
495 root.setAllowScriptAccess(mode);
498 it = _params.find("scale");
499 if (it != _params.end()) {
500 StringNoCaseEqual noCaseCompare;
501 const std::string& str = it->second;
502 movie_root::ScaleMode mode = movie_root::SCALEMODE_SHOWALL;
504 if (noCaseCompare(str, "noScale")) {
505 mode = movie_root::SCALEMODE_NOSCALE;
507 else if (noCaseCompare(str, "exactFit")) {
508 mode = movie_root::SCALEMODE_EXACTFIT;
510 else if (noCaseCompare(str, "noBorder")) {
511 mode = movie_root::SCALEMODE_NOBORDER;
514 log_debug("Setting scale mode");
515 root.setStageScaleMode(mode);
518 // Set up screenshots.
519 if (!_screenshots.empty()) {
520 std::istringstream is(_screenshots);
521 std::string arg;
522 bool last = false;
523 ScreenShotter::FrameList v;
525 while (std::getline(is, arg, ',')) {
526 if (arg == "last") last = true;
527 else try {
528 const size_t frame = boost::lexical_cast<size_t>(arg);
529 v.push_back(frame);
531 catch (const boost::bad_lexical_cast&) {}
534 // Use default if filename is empty.
535 if (_screenshotFile.empty()) {
536 URL url(_runResources->baseURL());
537 std::string::size_type p = url.path().rfind('/');
538 const std::string& name = (p == std::string::npos) ? url.path() :
539 url.path().substr(p + 1);
540 _screenshotFile = "screenshot-" + name + "-%f";
543 _gui->requestScreenShots(v, last, _screenshotFile);
546 _gui->run();
548 log_debug("Main loop ended, cleaning up");
550 // Clean up as much as possible, so valgrind will help find actual leaks.
551 gnash::clear();
555 void
556 Player::CallbacksHandler::exit()
558 _gui.quit();
561 void
562 Player::CallbacksHandler::error(const std::string& msg)
564 _gui.error(msg);
567 bool
568 Player::CallbacksHandler::yesNo(const std::string& query)
570 return _gui.yesno(query);
573 std::string
574 Player::CallbacksHandler::call(const std::string& event, const std::string& arg)
576 StringNoCaseEqual noCaseCompare;
578 if (event == "Mouse.hide") {
579 return _gui.showMouse(false) ? "true" : "false";
582 if (event == "Mouse.show") {
583 return _gui.showMouse(true) ? "true" : "false";
586 if (event == "Stage.displayState") {
587 if (arg == "fullScreen") _gui.setFullscreen();
588 else if (arg == "normal") _gui.unsetFullscreen();
589 return "";
592 if (event == "Stage.scaleMode" || event == "Stage.align" ) {
593 _gui.updateStageMatrix();
594 return "";
597 if (event == "Stage.showMenu") {
598 if (noCaseCompare(arg, "true")) _gui.showMenu(true);
599 else if (noCaseCompare(arg, "false")) _gui.showMenu(false);
600 return "";
603 if (event == "Stage.resize") {
604 if ( _gui.isPlugin() ) {
605 log_debug("Player doing nothing on Stage.resize as we're a plugin");
606 return "";
609 // arg contains WIDTHxHEIGHT
610 log_debug("Player got Stage.resize(%s) message", arg);
611 int width, height;
612 sscanf(arg.c_str(), "%dx%d", &width, &height);
613 _gui.resizeWindow(width, height);
615 return "";
618 if (event == "ExternalInterface.Play") {
619 _gui.play();
620 return "";
623 if (event == "ExternalInterface.StopPlay") {
624 _gui.pause();
625 return "";
628 if (event == "ExternalInterface.Rewind") {
629 _gui.restart();
630 return "";
633 if (event == "ExternalInterface.Pan") {
634 // FIXME: the 3 args are encoded as 1:2:0
635 log_unimpl("ExternalInterface.Pan");
636 return "";
639 if (event == "ExternalInterface.IsPlaying") {
640 return (_gui.isStopped()) ? "false" : "true";
643 if (event == "ExternalInterface.SetZoomRect") {
644 // FIXME: the 4 arguments are encoded as 1:2:0:1
645 log_unimpl("ExternalInterface.SetZoomRect");
646 return "";
649 if (event == "ExternalInterface.Zoom") {
650 // The 1 argument is a percentage to zoom
651 int percent = strtol(arg.c_str(), NULL, 0);
652 log_unimpl("ExternalInterface.Zoom(%d)", percent);
653 return "";
656 if (event == "System.capabilities.screenResolutionX") {
657 std::ostringstream ss;
658 ss << _gui.getScreenResX();
659 return ss.str();
662 if (event == "System.capabilities.screenResolutionY") {
663 std::ostringstream ss;
664 ss << _gui.getScreenResY();
665 return ss.str();
668 if (event == "System.capabilities.pixelAspectRatio") {
669 std::ostringstream ss;
670 // Whether the pp actively limits the precision or simply
671 // gets a slightly different result isn't clear.
672 ss << std::setprecision(7) << _gui.getPixelAspectRatio();
673 return ss.str();
676 if (event == "System.capabilities.screenDPI") {
677 std::ostringstream ss;
678 ss << _gui.getScreenDPI();
679 return ss.str();
682 if (event == "System.capabilities.screenColor") {
683 return _gui.getScreenColor();
686 if (event == "System.capabilities.playerType") {
687 return _gui.isPlugin() ? "PlugIn" : "StandAlone";
690 log_error(_("Unhandled callback %s with arguments %s"), event, arg);
691 return "";
694 void
695 Player::CallbacksHandler::notify(const std::string& command,
696 const std::string& args)
698 //log_debug(_("fs_callback(%p): %s %s"), (void*)movie, command, args);
700 gnash::RcInitFile& rcfile = gnash::RcInitFile::getDefaultInstance();
702 // it's _hostfd, but we're a static method...
703 const int hostfd = _player.getHostFD();
704 if (hostfd != -1) {
705 //log_debug("user-provided host requests fd is %d", hostfd);
706 std::stringstream request;
707 std::vector<as_value> fnargs;
708 fnargs.push_back(as_value(command));
709 fnargs.push_back(as_value(args));
710 request << ExternalInterface::makeInvoke("fsCommand", fnargs);
712 std::string requestString = request.str();
713 const char* cmd = requestString.c_str();
714 size_t len = requestString.length();
715 // TODO: should mutex-protect this ?
716 // NOTE: we assuming the hostfd is set in blocking mode here..
717 //log_debug("Attempt to write INVOKE requests fd %d", hostfd);
718 int ret = write(hostfd, cmd, len);
719 if ( ret == -1 ) {
720 log_error("Could not write to user-provided host "
721 "requests fd %d: %s", hostfd, strerror(errno));
723 if ( static_cast<size_t>(ret) < len ) {
724 log_error("Could only write %d bytes over %d required to "
725 "user-provided host requests fd %d",
726 ret, len, hostfd);
729 // Remove the newline for logging
730 requestString.resize(requestString.size() - 1);
731 log_debug(_("Sent FsCommand '%s' to host fd %d"),
732 requestString, hostfd);
735 /// Fscommands can be ignored using an rcfile setting. As a
736 /// plugin they are always ignored.
737 if (_gui.isPlugin()) {
738 // We log the request to the fd above
739 log_debug(_("Running as plugin: skipping internal "
740 "handling of FsCommand %s%s."));
741 return;
744 // This only disables fscommands for the standalone player. In the
745 // plugin or a hosting application, the fscommands are always passed
746 // on; the hosting application should decide what to do with them.
747 // (Or do we want to allow disabling all external communication?)
748 if (rcfile.ignoreFSCommand()) return;
750 StringNoCaseEqual noCaseCompare;
752 // There are six defined FsCommands handled by the standalone player:
753 // quit, fullscreen, showmenu, exec, allowscale, and trapallkeys.
755 // FSCommand quit
756 if (noCaseCompare(command, "quit")) {
757 _gui.quit();
758 return;
761 // FSCommand fullscreen
762 if (noCaseCompare(command, "fullscreen")) {
763 if (noCaseCompare(args, "true")) _gui.setFullscreen();
764 else if (noCaseCompare(args, "false")) _gui.unsetFullscreen();
765 return;
768 // FSCommand showmenu
769 if (noCaseCompare(command, "showmenu")) {
770 if (noCaseCompare(args, "true")) _gui.showMenu(true);
771 else if (noCaseCompare(args, "false")) _gui.showMenu(false);
772 return;
775 // FSCommand exec
776 // Note: the pp insists that the file to execute should be in
777 // a subdirectory 'fscommand' of the 'projector' executable's
778 // location. In SWF5 there were no restrictions.
779 if (noCaseCompare(command, "exec")) {
780 log_unimpl(_("FsCommand exec called with argument %s"), args);
781 return;
784 // FSCommand allowscale
785 if (noCaseCompare(command, "allowscale")) {
786 //log_debug("allowscale: %s", args);
787 if (noCaseCompare(args, "true")) _gui.allowScale(true);
788 else {
789 if (strtol(args.c_str(), NULL, 0)) _gui.allowScale(true);
790 else _gui.allowScale(false);
792 return;
795 // FSCommand trapallkeys
796 if (noCaseCompare(command, "trapallkeys")) {
797 log_unimpl(_("FsCommand trapallkeys called with argument %s"), args);
798 return;
801 // The plugin never reaches this point; anything sent to the fd has
802 // been logged already.
803 log_debug(_("FsCommand '%s(%s)' not handled internally"),
804 command, args);
809 // private
810 std::auto_ptr<Gui>
811 Player::getGui()
813 #ifdef GUI_GTK
814 return createGTKGui(_windowID, _scale, _doLoop, *_runResources);
815 #endif
817 #ifdef GUI_KDE3
818 return createKDEGui(_windowID, _scale, _doLoop, *_runResources);
819 #endif
821 #ifdef GUI_KDE4
822 return createKDE4Gui(_windowID, _scale, _doLoop, *_runResources);
823 #endif
825 #ifdef GUI_SDL
826 return createSDLGui(_windowID, _scale, _doLoop, *_runResources);
827 #endif
829 #ifdef GUI_AQUA
830 return createAQUAGui(_windowID, _scale, _doLoop, *_runResources);
831 #endif
833 #ifdef GUI_RISCOS
834 return createRISCOSGui(_windowID, _scale, _doLoop, *_runResources);
835 #endif
837 #ifdef GUI_FLTK
838 return createFLTKGui(_windowID, _scale, _doLoop, *_runResources);
839 #endif
841 #ifdef GUI_FB
842 return createFBGui(_windowID, _scale, _doLoop, *_runResources);
843 #endif
845 #ifdef GUI_AOS4
846 return createAOS4Gui(_windowID, _scale, _doLoop, *_runResources);
847 #endif
849 #ifdef GUI_HAIKU
850 return createHaikuGui(_windowID, _scale, _doLoop, *_runResources);
851 #endif
853 #ifdef GUI_DUMP
854 return createDumpGui(_windowID, _scale, _doLoop, *_runResources);
855 #endif
857 return std::auto_ptr<Gui>(new NullGui(_doLoop, *_runResources));
860 Player::~Player()
862 if (_movieDef.get()) {
863 log_debug("~Player - _movieDef refcount: %d (1 will be dropped "
864 "now)", _movieDef->get_ref_count());