Simplify commit extraction, and use abbreviated commit id
[gnash.git] / gui / Player.cpp
blobc3d2ea6f37b00d57082061142d977e4184a07ab5
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"
51 #include "ScreenShotter.h"
53 #include "GnashSystemIOHeaders.h" // for write()
54 #include "log.h"
55 #include <iostream>
56 #include <sstream>
57 #include <iomanip>
58 #include <boost/lexical_cast.hpp>
60 using namespace gnash;
62 namespace {
63 gnash::LogFile& dbglogfile = gnash::LogFile::getDefaultInstance();
66 void
67 Player::setFlashVars(const std::string& varstr)
69 typedef Gui::VariableMap maptype;
71 maptype vars;
72 URL::parse_querystring(varstr, vars);
74 _gui->addFlashVars(vars);
77 Player::Player()
79 #if defined(RENDERER_CAIRO)
80 _bitDepth(32),
81 #else
82 _bitDepth(16),
83 #endif
84 _scale(1.0f),
85 _delay(0),
86 _width(0),
87 _height(0),
88 _xPosition(-1),
89 _yPosition(-1),
90 _windowID(0),
91 _doLoop(true),
92 _doRender(true),
93 _doSound(true),
94 _exitTimeout(0),
95 _movieDef(0),
96 _maxAdvances(0),
97 #ifdef GNASH_FPS_DEBUG
98 _fpsDebugTime(0.0),
99 #endif
100 _hostfd(-1),
101 _controlfd(-1),
102 _startFullscreen(false),
103 _hideMenu(false),
104 _screenshotQuality(100)
108 float
109 Player::setScale(float newscale)
111 float oldscale = _scale;
112 _scale = newscale;
113 return oldscale;
116 void
117 Player::init_logfile()
119 dbglogfile.setWriteDisk(false);
121 RcInitFile& rcfile = RcInitFile::getDefaultInstance();
122 if (rcfile.useWriteLog()) {
123 dbglogfile.setWriteDisk(true);
126 dbglogfile.setLogFilename(rcfile.getDebugLog());
128 if (rcfile.verbosityLevel() > 0) {
129 dbglogfile.setVerbosity(rcfile.verbosityLevel());
132 if (rcfile.useActionDump()) {
133 dbglogfile.setActionDump(true);
134 dbglogfile.setVerbosity();
137 if (rcfile.useParserDump()) {
138 dbglogfile.setParserDump(true);
139 dbglogfile.setVerbosity();
142 // If a delay was not specified yet use
143 // any eventual setting for it found in
144 // the RcInitFile
146 // TODO: we should remove all uses of the rcfile
147 // from Player class..
149 if (!_delay && rcfile.getTimerDelay() > 0) {
150 _delay = rcfile.getTimerDelay();
151 log_debug (_("Timer delay set to %d milliseconds"), _delay);
156 void
157 Player::init_sound()
160 if (_doSound) {
161 try {
162 #ifdef SOUND_SDL
163 _soundHandler.reset(sound::create_sound_handler_sdl(
164 _mediaHandler.get()));
165 #elif defined(SOUND_AHI)
166 _soundHandler.reset(sound::create_sound_handler_aos4(
167 _mediaHandler.get()));
168 #elif defined(SOUND_MKIT)
169 _soundHandler.reset(sound::create_sound_handler_mkit(
170 _mediaHandler.get()));
171 #else
172 log_error(_("Sound requested but no sound support compiled in"));
173 return;
174 #endif
176 } catch (SoundException& ex) {
177 log_error(_("Could not create sound handler: %s."
178 " Will continue w/out sound."), ex.what());
183 void
184 Player::init_gui()
186 if (_doRender) {
187 _gui = getGui();
188 } else {
189 _gui.reset(new NullGui(_doLoop, *_runResources));
192 _gui->setAudioDump(_audioDump);
193 _gui->setMaxAdvances(_maxAdvances);
195 #ifdef GNASH_FPS_DEBUG
196 if (_fpsDebugTime) {
197 log_debug(_("Activating FPS debugging every %g seconds"),
198 _fpsDebugTime);
199 _gui->setFpsTimerInterval(_fpsDebugTime);
201 #endif
204 boost::intrusive_ptr<movie_definition>
205 Player::load_movie()
207 /// The RunResources must be initialized by this point to provide resources
208 /// for parsing.
209 assert(_runResources.get());
211 boost::intrusive_ptr<gnash::movie_definition> md;
213 RcInitFile& rcfile = RcInitFile::getDefaultInstance();
214 URL vurl(_url);
216 if (vurl.protocol() == "file") {
217 const std::string& path = vurl.path();
218 size_t lastSlash = path.find_last_of('/');
219 std::string dir = path.substr(0, lastSlash+1);
220 rcfile.addLocalSandboxPath(dir);
221 log_debug(_("%s appended to local sandboxes"), dir.c_str());
224 try {
225 if (_infile == "-") {
226 std::auto_ptr<IOChannel> in (
227 noseek_fd_adapter::make_stream(fileno(stdin)));
228 md = MovieFactory::makeMovie(in, _url, *_runResources, false);
230 else {
231 URL url(_infile);
232 if ( url.protocol() == "file" ) {
233 std::string path = url.path();
234 // We'll need to allow load of the file, no matter virtual url
235 // specified...
236 // This is kind of hackish, cleaner would be adding an argument
237 // to createMovie to skip the security checking phase.
238 // NOTE that if we fail to allow this load, the konqueror plugin
239 // would not be able to load anything
241 rcfile.addLocalSandboxPath(path);
242 log_debug(_("%s appended to local sandboxes"), path.c_str());
245 // _url should be always set at this point...
246 md = MovieFactory::makeMovie(url, *_runResources, _url.c_str(),
247 false);
250 catch (const GnashException& er) {
251 std::cerr << er.what() << std::endl;
252 md = NULL;
255 if (!md) {
256 fprintf(stderr, "Could not load movie '%s'\n", _infile.c_str());
257 return NULL;
260 return md;
263 /// \brief Run, used to open a new flash file. Using previous initialization
264 void
265 Player::run(int argc, char* argv[], const std::string& infile,
266 const std::string& url)
268 // Call this at run() time, so the caller has
269 // a cache of setting some parameter before calling us...
270 // (example: setDoSound(), setWindowId() etc.. )
271 init_logfile();
273 // gnash.cpp should check that a filename is supplied.
274 assert (!infile.empty());
276 _infile = infile;
278 // Work out base url
279 if (_baseurl.empty()) {
280 if (!url.empty()) _baseurl = url;
281 else if (infile == "-") _baseurl = URL("./").str();
282 else _baseurl = infile;
285 // Set _root._url (either explicit of from infile)
286 if (!url.empty()) {
287 _url = url;
288 } else {
289 _url = infile;
292 // Parse player parameters. These are not passed to the SWF, but rather
293 // control stage properties etc.
294 // NOTE: it is intentional to force a trailing slash to "base" argument
295 // as it was tested that the "base" argument is always considered
296 // a directory!
297 Params::const_iterator it = _params.find("base");
298 const URL baseURL = (it == _params.end()) ? _baseurl :
299 URL(it->second+"/", _baseurl);
300 /// The RunResources should be populated before parsing.
301 _runResources.reset(new RunResources());
303 boost::shared_ptr<SWF::TagLoadersTable> loaders(new SWF::TagLoadersTable());
304 addDefaultLoaders(*loaders);
305 _runResources->setTagLoaders(loaders);
307 std::auto_ptr<NamingPolicy> np(new IncrementalRename(_baseurl));
309 /// The StreamProvider uses the actual URL of the loaded movie.
310 boost::shared_ptr<StreamProvider> sp(new StreamProvider(_url, baseURL, np));
312 _runResources->setStreamProvider(sp);
314 // Set the Hardware video decoding resources. none, vaapi, omap
315 _runResources->setHWAccelBackend(_hwaccel);
316 // Set the Renderer resource, opengl, agg, or cairo
317 _runResources->setRenderBackend(_renderer);
319 _mediaHandler.reset(media::MediaFactory::instance().get(_media));
321 if (!_mediaHandler.get()) {
322 boost::format fmt =
323 boost::format(_("Non-existent media handler %1% specified"))
324 % _media;
325 throw GnashException(fmt.str());
328 _runResources->setMediaHandler(_mediaHandler);
330 init_sound();
331 _runResources->setSoundHandler(_soundHandler);
333 init_gui();
335 // Initialize gui (we need argc/argv for this)
336 // note that this will also initialize the renderer
337 // which is *required* during movie loading
338 if (!_gui->init(argc, &argv)) {
339 throw GnashException("Could not initialize GUI");
342 // Parse querystring (before FlashVars, see
343 // testsuite/misc-ming.all/FlashVarsTest*)
344 setFlashVars(URL(_url).querystring());
346 // Add FlashVars.
347 Params::const_iterator fv = _params.find("flashvars");
348 if (fv != _params.end()) {
349 setFlashVars(fv->second);
352 // Load the actual movie.
353 _movieDef = load_movie();
354 if (!_movieDef) {
355 throw GnashException("Could not load movie!");
358 // Get info about the width & height of the movie.
359 const size_t movie_width = _movieDef->get_width_pixels();
360 const size_t movie_height = _movieDef->get_height_pixels();
362 if (! _width) {
363 _width = static_cast<size_t>(movie_width * _scale);
365 if (! _height) {
366 _height = static_cast<size_t>(movie_height * _scale);
369 if (!_width || !_height) {
370 log_debug(_("Input movie has collapsed dimensions "
371 "%d/%d. Setting to 1/1 and going on."),
372 _width, _height);
373 if (!_width) _width = 1;
374 if (!_height) _height = 1;
377 // Register movie definition before creating the window
378 _gui->setMovieDefinition(_movieDef.get());
380 // Now that we know about movie size, create gui window.
381 _gui->createWindow(_url.c_str(), _width, _height, _xPosition, _yPosition);
383 movie_root root(*_movieDef, _gui->getClock(), *_runResources);
385 _callbacksHandler.reset(new CallbacksHandler(*_gui, *this));
387 // Register Player to receive events from the core (Mouse, Stage,
388 // System etc)
389 root.registerEventCallback(_callbacksHandler.get());
391 // Register Player to receive FsCommand events from the core.
392 root.registerFSCommandCallback(_callbacksHandler.get());
394 log_debug("Player Host FD #%d, Player Control FD #%d",
395 _hostfd, _controlfd);
397 // Set host requests fd (if any)
398 if ( _hostfd != -1 ) {
399 root.setHostFD(_hostfd);
402 if (_controlfd != -1) {
403 root.setControlFD(_controlfd);
406 _gui->setStage(&root);
408 // When startStopped is true, stop here after the stage has been
409 // registered, but before the movie has started. Initial loading
410 // and VM initialization have been done by this stage, but not
411 // the complete parsing of the SWF. This is important because
412 // the Gui accesses movie_root to get the sound_handler, but also
413 // because the gui window should be properly set up by this point.
414 RcInitFile& rcfile = RcInitFile::getDefaultInstance();
416 if (rcfile.startStopped()) {
417 _gui->stop();
420 // Start loader thread
421 // NOTE: the loader thread might (in IMPORT tag parsing)
422 // create new movies and register them to the MovieLibrary.
423 // If MovieLibrary size exceeded, _movieDef might be
424 // destroyed prematurely. movie_root might actually be
425 // keeping it alive, as Gui might as well, but why relying
426 // on luck ? So we made sure to keep _movieDef by
427 // intrusive_ptr...
428 _movieDef->completeLoad();
430 if (! _delay) {
431 // 10ms per heart beat
432 _delay = 10;
434 _gui->setInterval(_delay);
436 if (_exitTimeout) {
437 _gui->setTimeout(static_cast<unsigned int>(_exitTimeout * 1000));
440 if (!_windowID && _startFullscreen) {
441 _gui->setFullscreen();
444 if (!_windowID && _hideMenu) {
445 _gui->hideMenu();
448 // Now handle stage alignment and scale mode. This should be done after
449 // the GUI is created, after its stage member is set, and after the
450 // interface callbacks are registered.
451 it = _params.find("salign");
452 if (it != _params.end()) {
453 log_debug("Setting align");
454 const short align = stringToStageAlign(it->second);
455 root.setStageAlignment(align);
458 it = _params.find("allowscriptaccess");
459 if (it != _params.end()) {
460 std::string access = it->second;
461 StringNoCaseEqual noCaseCompare;
462 const std::string& str = it->second;
464 movie_root::AllowScriptAccessMode mode =
465 movie_root::SCRIPT_ACCESS_SAME_DOMAIN;
467 if (noCaseCompare(str, "never")) {
468 mode = movie_root::SCRIPT_ACCESS_NEVER;
470 else if (noCaseCompare(str, "sameDomain")) {
471 mode = movie_root::SCRIPT_ACCESS_SAME_DOMAIN;
473 else if (noCaseCompare(str, "always")) {
474 mode = movie_root::SCRIPT_ACCESS_ALWAYS;
476 log_debug("Setting allowscriptaccess to %s", mode);
477 root.setAllowScriptAccess(mode);
480 it = _params.find("scale");
481 if (it != _params.end()) {
482 StringNoCaseEqual noCaseCompare;
483 const std::string& str = it->second;
484 movie_root::ScaleMode mode = movie_root::SCALEMODE_SHOWALL;
486 if (noCaseCompare(str, "noScale")) {
487 mode = movie_root::SCALEMODE_NOSCALE;
489 else if (noCaseCompare(str, "exactFit")) {
490 mode = movie_root::SCALEMODE_EXACTFIT;
492 else if (noCaseCompare(str, "noBorder")) {
493 mode = movie_root::SCALEMODE_NOBORDER;
496 log_debug("Setting scale mode");
497 root.setStageScaleMode(mode);
500 // Set up screenshots.
501 if (!_screenshots.empty()) {
502 std::istringstream is(_screenshots);
503 std::string arg;
504 bool last = false;
505 ScreenShotter::FrameList v;
507 while (std::getline(is, arg, ',')) {
508 if (arg == "last") last = true;
509 else try {
510 const size_t frame = boost::lexical_cast<size_t>(arg);
511 v.push_back(frame);
513 catch (const boost::bad_lexical_cast&) {}
516 // Use default if filename is empty.
517 if (_screenshotFile.empty()) {
518 URL url(_runResources->streamProvider().baseURL());
519 std::string::size_type p = url.path().rfind('/');
520 const std::string& name = (p == std::string::npos) ? url.path() :
521 url.path().substr(p + 1);
522 _screenshotFile = "screenshot-" + name + "-%f";
524 if (!last && v.empty()) return;
526 std::auto_ptr<ScreenShotter> ss(new ScreenShotter(_screenshotFile, _screenshotQuality));
527 if (last) ss->lastFrame();
528 ss->setFrames(v);
529 _gui->setScreenShotter(ss);
532 _gui->run();
534 log_debug("Main loop ended, cleaning up");
536 // Clean up as much as possible, so valgrind will help find actual leaks.
537 MovieFactory::clear();
541 void
542 Player::CallbacksHandler::exit()
544 _gui.quit();
547 void
548 Player::CallbacksHandler::error(const std::string& msg)
550 _gui.error(msg);
553 bool
554 Player::CallbacksHandler::yesNo(const std::string& query)
556 return _gui.yesno(query);
559 std::string
560 Player::CallbacksHandler::call(const std::string& event, const std::string& arg)
562 StringNoCaseEqual noCaseCompare;
564 if (event == "Mouse.hide") {
565 return _gui.showMouse(false) ? "true" : "false";
568 if (event == "Mouse.show") {
569 return _gui.showMouse(true) ? "true" : "false";
572 if (event == "Stage.displayState") {
573 if (arg == "fullScreen") _gui.setFullscreen();
574 else if (arg == "normal") _gui.unsetFullscreen();
575 return "";
578 if (event == "Stage.scaleMode" || event == "Stage.align" ) {
579 _gui.updateStageMatrix();
580 return "";
583 if (event == "Stage.showMenu") {
584 if (noCaseCompare(arg, "true")) _gui.showMenu(true);
585 else if (noCaseCompare(arg, "false")) _gui.showMenu(false);
586 return "";
589 if (event == "Stage.resize") {
590 if ( _gui.isPlugin() ) {
591 log_debug("Player doing nothing on Stage.resize as we're a plugin");
592 return "";
595 // arg contains WIDTHxHEIGHT
596 log_debug("Player got Stage.resize(%s) message", arg);
597 int width, height;
598 sscanf(arg.c_str(), "%dx%d", &width, &height);
599 _gui.resizeWindow(width, height);
601 return "";
604 if (event == "ExternalInterface.Play") {
605 _gui.play();
606 return "";
609 if (event == "ExternalInterface.StopPlay") {
610 _gui.pause();
611 return "";
614 if (event == "ExternalInterface.Rewind") {
615 _gui.restart();
616 return "";
619 if (event == "ExternalInterface.Pan") {
620 // FIXME: the 3 args are encoded as 1:2:0
621 log_unimpl("ExternalInterface.Pan");
622 return "";
625 if (event == "ExternalInterface.IsPlaying") {
626 return (_gui.isStopped()) ? "false" : "true";
629 if (event == "ExternalInterface.SetZoomRect") {
630 // FIXME: the 4 arguments are encoded as 1:2:0:1
631 log_unimpl("ExternalInterface.SetZoomRect");
632 return "";
635 if (event == "ExternalInterface.Zoom") {
636 // The 1 argument is a percentage to zoom
637 int percent = strtol(arg.c_str(), NULL, 0);
638 log_unimpl("ExternalInterface.Zoom(%d)", percent);
639 return "";
642 if (event == "System.capabilities.screenResolutionX") {
643 std::ostringstream ss;
644 ss << _gui.getScreenResX();
645 return ss.str();
648 if (event == "System.capabilities.screenResolutionY") {
649 std::ostringstream ss;
650 ss << _gui.getScreenResY();
651 return ss.str();
654 if (event == "System.capabilities.pixelAspectRatio") {
655 std::ostringstream ss;
656 // Whether the pp actively limits the precision or simply
657 // gets a slightly different result isn't clear.
658 ss << std::setprecision(7) << _gui.getPixelAspectRatio();
659 return ss.str();
662 if (event == "System.capabilities.screenDPI") {
663 std::ostringstream ss;
664 ss << _gui.getScreenDPI();
665 return ss.str();
668 if (event == "System.capabilities.screenColor") {
669 return _gui.getScreenColor();
672 if (event == "System.capabilities.playerType") {
673 return _gui.isPlugin() ? "PlugIn" : "StandAlone";
676 log_error(_("Unhandled callback %s with arguments %s"), event, arg);
677 return "";
680 void
681 Player::CallbacksHandler::notify(const std::string& command,
682 const std::string& args)
684 //log_debug(_("fs_callback(%p): %s %s"), (void*)movie, command, args);
686 gnash::RcInitFile& rcfile = gnash::RcInitFile::getDefaultInstance();
688 // it's _hostfd, but we're a static method...
689 const int hostfd = _player.getHostFD();
690 if (hostfd != -1) {
691 //log_debug("user-provided host requests fd is %d", hostfd);
692 std::stringstream request;
693 std::vector<as_value> fnargs;
694 fnargs.push_back(as_value(command));
695 fnargs.push_back(as_value(args));
696 request << ExternalInterface::makeInvoke("fsCommand", fnargs);
698 std::string requestString = request.str();
699 const char* cmd = requestString.c_str();
700 size_t len = requestString.length();
701 // TODO: should mutex-protect this ?
702 // NOTE: we assuming the hostfd is set in blocking mode here..
703 //log_debug("Attempt to write INVOKE requests fd %d", hostfd);
704 int ret = write(hostfd, cmd, len);
705 if ( ret == -1 ) {
706 log_error("Could not write to user-provided host "
707 "requests fd %d: %s", hostfd, strerror(errno));
709 if ( static_cast<size_t>(ret) < len ) {
710 log_error("Could only write %d bytes over %d required to "
711 "user-provided host requests fd %d",
712 ret, len, hostfd);
715 // Remove the newline for logging
716 requestString.resize(requestString.size() - 1);
717 log_debug(_("Sent FsCommand '%s' to host fd %d"),
718 requestString, hostfd);
721 /// Fscommands can be ignored using an rcfile setting. As a
722 /// plugin they are always ignored.
723 if (_gui.isPlugin()) {
724 // We log the request to the fd above
725 log_debug(_("Running as plugin: skipping internal "
726 "handling of FsCommand %s%s."));
727 return;
730 // This only disables fscommands for the standalone player. In the
731 // plugin or a hosting application, the fscommands are always passed
732 // on; the hosting application should decide what to do with them.
733 // (Or do we want to allow disabling all external communication?)
734 if (rcfile.ignoreFSCommand()) return;
736 StringNoCaseEqual noCaseCompare;
738 // There are six defined FsCommands handled by the standalone player:
739 // quit, fullscreen, showmenu, exec, allowscale, and trapallkeys.
741 // FSCommand quit
742 if (noCaseCompare(command, "quit")) {
743 _gui.quit();
744 return;
747 // FSCommand fullscreen
748 if (noCaseCompare(command, "fullscreen")) {
749 if (noCaseCompare(args, "true")) _gui.setFullscreen();
750 else if (noCaseCompare(args, "false")) _gui.unsetFullscreen();
751 return;
754 // FSCommand showmenu
755 if (noCaseCompare(command, "showmenu")) {
756 if (noCaseCompare(args, "true")) _gui.showMenu(true);
757 else if (noCaseCompare(args, "false")) _gui.showMenu(false);
758 return;
761 // FSCommand exec
762 // Note: the pp insists that the file to execute should be in
763 // a subdirectory 'fscommand' of the 'projector' executable's
764 // location. In SWF5 there were no restrictions.
765 if (noCaseCompare(command, "exec")) {
766 log_unimpl(_("FsCommand exec called with argument %s"), args);
767 return;
770 // FSCommand allowscale
771 if (noCaseCompare(command, "allowscale")) {
772 //log_debug("allowscale: %s", args);
773 if (noCaseCompare(args, "true")) _gui.allowScale(true);
774 else {
775 if (strtol(args.c_str(), NULL, 0)) _gui.allowScale(true);
776 else _gui.allowScale(false);
778 return;
781 // FSCommand trapallkeys
782 if (noCaseCompare(command, "trapallkeys")) {
783 log_unimpl(_("FsCommand trapallkeys called with argument %s"), args);
784 return;
787 // The plugin never reaches this point; anything sent to the fd has
788 // been logged already.
789 log_debug(_("FsCommand '%s(%s)' not handled internally"),
790 command, args);
795 // private
796 std::auto_ptr<Gui>
797 Player::getGui()
799 #ifdef GUI_GTK
800 return createGTKGui(_windowID, _scale, _doLoop, *_runResources);
801 #endif
803 #ifdef GUI_KDE3
804 return createKDEGui(_windowID, _scale, _doLoop, *_runResources);
805 #endif
807 #ifdef GUI_KDE4
808 return createKDE4Gui(_windowID, _scale, _doLoop, *_runResources);
809 #endif
811 #ifdef GUI_SDL
812 return createSDLGui(_windowID, _scale, _doLoop, *_runResources);
813 #endif
815 #ifdef GUI_AQUA
816 return createAQUAGui(_windowID, _scale, _doLoop, *_runResources);
817 #endif
819 #ifdef GUI_RISCOS
820 return createRISCOSGui(_windowID, _scale, _doLoop, *_runResources);
821 #endif
823 #ifdef GUI_FLTK
824 return createFLTKGui(_windowID, _scale, _doLoop, *_runResources);
825 #endif
827 #ifdef GUI_FB
828 return createFBGui(_windowID, _scale, _doLoop, *_runResources);
829 #endif
831 #ifdef GUI_AOS4
832 return createAOS4Gui(_windowID, _scale, _doLoop, *_runResources);
833 #endif
835 #ifdef GUI_HAIKU
836 return createHaikuGui(_windowID, _scale, _doLoop, *_runResources);
837 #endif
839 #ifdef GUI_DUMP
840 return createDumpGui(_windowID, _scale, _doLoop, *_runResources);
841 #endif
843 return std::auto_ptr<Gui>(new NullGui(_doLoop, *_runResources));
846 Player::~Player()
848 if (_movieDef.get()) {
849 log_debug("~Player - _movieDef refcount: %d (1 will be dropped "
850 "now)", _movieDef->get_ref_count());