Backslash ${prefix} for kde3 too...
[gnash.git] / gui / gnash.cpp
blob2f760b90c7219ec126fe6dfaa78f10bdeef33880
1 // gnash.cpp: Main routine for 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 #include <string>
26 #include <iostream>
27 #include <iterator>
28 #include <ios>
29 #include <boost/format.hpp>
30 #include <boost/program_options.hpp>
31 #include <boost/algorithm/string/join.hpp>
32 #include <boost/algorithm/string/split.hpp>
33 #include <boost/algorithm/string/classification.hpp>
34 #include <boost/function.hpp>
35 #include <cstdlib>
36 #include <utility>
37 #include <functional>
38 #ifdef ENABLE_NLS
39 # include <clocale>
40 #endif
42 #include "Player.h"
43 #include "log.h"
44 #include "rc.h" // for use of rcfile
45 #include "GnashNumeric.h" // for clamp
46 #include "GnashException.h"
47 #include "revno.h"
48 #include "MediaHandler.h"
50 using std::endl;
51 using std::cout;
53 std::vector<std::string> infiles;
54 std::string url;
56 namespace gnash {
57 class Player;
60 namespace {
61 gnash::LogFile& dbglogfile = gnash::LogFile::getDefaultInstance();
62 gnash::RcInitFile& rcfile = gnash::RcInitFile::getDefaultInstance();
65 // Forward declarations
66 namespace {
67 namespace po = boost::program_options;
68 po::options_description getSupportedOptions(gnash::Player& p);
70 void setupSoundAndRendering(gnash::Player& p, int i);
71 void setupFlashVars(gnash::Player& p,
72 const std::vector<std::string>& params);
73 void setupFDs(gnash::Player& p, const std::string& fds);
75 void usage_gui_keys(std::ostream& os);
76 void usage(std::ostream& os, const po::options_description& opts);
77 void build_options(std::ostream& os);
78 void version_and_copyright(std::ostream& os);
81 namespace {
83 /// An accumulating option value to handle multiple -v options.
84 template<typename T>
85 class accumulator_type : public po::value_semantic {
86 public:
88 accumulator_type() : _interval(1), _default(0) {}
90 /// Set the notifier function.
91 accumulator_type* notifier(boost::function1<void, const T&> f) {
92 _notifier = f;
93 return this;
96 /// Set the default value for this option.
97 accumulator_type* default_value(const T& t) {
98 _default = t;
99 return this;
102 /// Set the implicit value for this option.
104 /// Unlike for program_options::value, this specifies a value
105 /// to be applied on each occurence of the option.
106 accumulator_type* implicit_value(const T& t) {
107 _interval = t;
108 return this;
111 virtual std::string name() const {
112 return std::string();
115 /// There are no tokens for an accumulator_type
116 virtual unsigned min_tokens() const { return 0; }
117 virtual unsigned max_tokens() const { return 0; }
119 // Accumulating from different sources is silly.
120 virtual bool is_composing() const {
121 return false;
124 virtual bool is_required() const { return false; }
126 virtual void parse(boost::any& value_store,
127 const std::vector<std::string>& new_tokens,
128 bool /*utf8*/) const
130 assert(new_tokens.empty());
131 if (value_store.empty()) value_store = T();
132 boost::any_cast<T&>(value_store) += _interval;
135 virtual bool apply_default(boost::any& value_store) const {
136 value_store = _default;
137 return true;
140 virtual void notify(const boost::any& value_store) const {
141 _notifier(boost::any_cast<T>(value_store));
144 virtual ~accumulator_type() {}
146 private:
147 boost::function1<void, const T&> _notifier;
148 T _interval;
149 T _default;
152 template<typename T>
153 accumulator_type<T>* accumulator() {
154 return new accumulator_type<T>();
160 main(int argc, char *argv[])
163 std::ios::sync_with_stdio(false);
165 // Enable native language support, i.e. internationalization
166 #ifdef ENABLE_NLS
167 std::setlocale (LC_ALL, "");
168 bindtextdomain (PACKAGE, LOCALEDIR);
169 textdomain (PACKAGE);
170 #endif
172 gnash::Player player;
174 po::options_description opts = getSupportedOptions(player);
176 // Add all positional arguments as input files.
177 po::positional_options_description files;
178 files.add("input-file", -1);
180 namespace cls = po::command_line_style;
182 po::variables_map vm;
183 try {
184 po::store(po::command_line_parser(argc, argv)
185 .options(opts)
186 .positional(files)
187 .style(cls::default_style ^ cls::allow_guessing)
188 .run(), vm);
190 catch (const po::error& e) {
191 std::cerr << boost::format(_("Error parsing options: %s\n"))
192 % e.what();
193 return EXIT_FAILURE;
196 po::notify(vm);
198 if (vm.count("help")) {
199 version_and_copyright(std::cout);
200 usage(std::cout, opts);
201 return EXIT_SUCCESS;
204 if (vm.count("version")) {
205 version_and_copyright(std::cout);
206 build_options(std::cout);
207 return EXIT_SUCCESS;
210 // Do some extra sanity checks on the options.
211 const bool plugin = vm.count("xid");
213 if (plugin && vm.count("height") && vm.count("width") &&
214 !player.getHeight() && !player.getWidth()) {
215 // We were given dimensions of 0x0 to render to (probably the plugin
216 // is playing an "invisible" movie. Disable video rendering.
217 player.setDoRender(false);
220 if (!vm.count("render-mode")) {
221 std::cerr << "Using rcfile\n";
222 if (plugin) {
223 player.setDoSound(rcfile.usePluginSound());
225 else {
226 player.setDoSound(rcfile.useSound());
230 // No file name was supplied
231 if (infiles.empty()) {
232 std::cerr << _("Error: no input file was specified. Exiting.\n");
233 usage(std::cerr, opts);
234 return EXIT_FAILURE;
237 // We only expect GnashExceptions here. No others should be thrown!
238 try {
239 player.run(argc, argv, infiles.front(), url);
241 catch (const gnash::GnashException& ex) {
242 std::cerr << "Error: " << ex.what() << "\n";
243 return EXIT_FAILURE;
245 return EXIT_SUCCESS;
248 namespace {
250 void
251 setupFlashVars(gnash::Player& p, const std::vector<std::string>& params)
253 for (std::vector<std::string>::const_iterator i = params.begin(),
254 e = params.end(); i != e; ++i) {
255 const std::string& param = *i;
256 const size_t eq = param.find("=");
257 if (eq == std::string::npos) {
258 p.setParam(param, "true");
259 return;
261 const std::string name = param.substr(0, eq);
262 const std::string value = param.substr(eq + 1);
263 p.setParam(name, value);
267 void
268 setupFDs(gnash::Player& p, const std::string& fds)
270 int hostfd = 0, controlfd = 0;
271 hostfd = std::strtol(fds.substr(0, fds.find(":")).c_str(), NULL, 0);
272 std::string csub = fds.substr(fds.find(":")+1, fds.size());
273 controlfd = strtol(csub.c_str(), 0, 0);
274 gnash::log_debug(_("Host FD #%d, Control FD #%d\n"),
275 hostfd, controlfd);
277 if (hostfd < 0) {
278 std::cerr << boost::format(_("Invalid host communication "
279 "filedescriptor %1%\n")) % hostfd;
280 std::exit(EXIT_FAILURE);
282 p.setHostFD(hostfd);
284 if (controlfd < 0) {
285 std::cerr << boost::format(_("Invalid control communication "
286 "filedescriptor %1%\n")) % controlfd;
287 std::exit(EXIT_FAILURE);
289 p.setControlFD(controlfd);
292 void
293 setupSoundAndRendering(gnash::Player& p, int i)
295 switch (i) {
296 case 0:
297 // Disable both
298 p.setDoRender(false);
299 p.setDoSound(false);
300 return;
301 case 1:
302 // Enable rendering, disable sound
303 p.setDoRender(true);
304 p.setDoSound(false);
305 return;
306 case 2:
307 // Enable sound, disable rendering
308 p.setDoRender(false);
309 p.setDoSound(true);
310 return;
311 case 3:
312 // Enable render & sound
313 p.setDoRender(true);
314 p.setDoSound(true);
315 return;
316 default:
317 gnash::log_error(_("ERROR: -r must be followed by "
318 "0, 1, 2 or 3 "));
323 po::options_description
324 getSupportedOptions(gnash::Player& p)
326 using std::string;
327 using gnash::Player;
328 using gnash::LogFile;
329 using gnash::RcInitFile;
331 std::vector<std::string> handlers;
332 gnash::media::MediaFactory::instance().listKeys(back_inserter(handlers));
334 std::vector<std::string> renderers;
335 boost::split(renderers, RENDERER_CONFIG,
336 boost::is_any_of(" "), boost::token_compress_on);
338 po::options_description desc(_("Options"));
340 desc.add_options()
342 ("help,h",
343 _("Print this help and exit"))
345 ("version,V",
346 _("Print version information and exit"))
348 ("scale,s", po::value<float>()
349 ->notifier(boost::bind(&Player::setScale, &p,
350 boost::bind(gnash::clamp<float>, _1, 0.01f, 100.f))),
351 _("Scale the movie by the specified factor"))
353 ("delay,d", po::value<int>()
354 ->notifier(boost::bind(&Player::setDelay, &p, _1)),
355 _("Number of milliseconds to delay in main loop"))
357 ("verbose,v", accumulator<int>()
358 ->notifier(boost::bind(&LogFile::setVerbosity, &dbglogfile, _1)),
359 _("Produce verbose output"))
361 #if VERBOSE_ACTION
362 ("verbose-actions,a", po::bool_switch()
363 ->notifier(boost::bind(&LogFile::setActionDump, &dbglogfile, _1)),
364 _("Be (very) verbose about action execution"))
365 #endif
367 #if VERBOSE_PARSE
368 ("verbose-parsing,p", po::bool_switch()
369 ->notifier(boost::bind(&LogFile::setParserDump, &dbglogfile, _1)),
370 _("Be (very) verbose about parsing"))
371 #endif
373 ("audio-dump,A", po::value<string>()
374 ->notifier(boost::bind(&Player::setAudioDumpfile, &p, _1)),
375 _("Audio dump file (wave format)"))
377 ("hwaccel", po::value<string>()
378 ->default_value("none")
379 ->notifier(boost::bind(&Player::setHWAccel, &p, _1)),
380 (string(_("Hardware Video Accelerator to use"))
381 + string("\nnone|vaapi")). c_str())
383 ("xid,x", po::value<long>()
384 ->notifier(boost::bind(&Player::setWindowId, &p, _1)),
385 _("X11 Window ID for display"))
387 ("writelog,w", po::bool_switch()
388 ->notifier(boost::bind(&RcInitFile::useWriteLog, &rcfile, _1)),
389 _("Produce the disk based debug log"))
391 ("width,j", po::value<int>()
392 ->notifier(boost::bind(&Player::setWidth, &p, _1)),
393 _("Set window width"))
395 ("height,k", po::value<int>()
396 ->notifier(boost::bind(&Player::setHeight, &p, _1)),
397 _("Set window height"))
399 ("x-pos,X", po::value<int>()
400 ->notifier(boost::bind(&Player::setXPosition, &p, _1)),
401 _("Set window x position"))
403 ("y-pos,Y", po::value<int>()
404 ->notifier(boost::bind(&Player::setYPosition, &p, _1)),
405 _("Set window y position"))
407 ("once,1", po::bool_switch()
408 ->notifier(boost::bind(&Player::setDoLoop, &p,
409 boost::bind(std::logical_not<bool>(), _1))),
410 _("Exit when/if movie reaches the last frame"))
412 ("render-mode,r", po::value<int>()
413 ->default_value(3)
414 ->notifier(boost::bind(&setupSoundAndRendering, boost::ref(p), _1)),
415 (string("0 ")
416 + string(_("disable rendering and sound"))
417 + string("\n1 ")
418 + string(_("enable rendering, disable sound"))
419 + string("\n2 ")
420 + string(_("enable sound, disable rendering"))
421 + string("\n3 ")
422 + string(_("enable rendering and sound"))
423 ).c_str())
425 ("media,M", po::value<string>()
426 ->default_value(handlers.front())
427 ->notifier(boost::bind(&Player::setMedia, &p, _1)),
428 (string(_("The media handler to use"))
429 + string("\n") + boost::join(handlers, "|")
430 ).c_str())
432 ("renderer,R", po::value<string>()
433 ->default_value("agg")
434 ->notifier(boost::bind(&Player::setRenderer, &p, _1)),
435 (string(_("The renderer to use"))
436 + string("\n") + boost::join(renderers, "|")
437 ).c_str())
439 ("timeout,t", po::value<float>()
440 ->notifier(boost::bind(&Player::setExitTimeout, &p, _1)),
441 _("Exit after the specified number of seconds"))
443 ("real-url,u", po::value<string>(&url),
444 _("Set \"real\" URL of the movie"))
446 ("base-url,U", po::value<string>()
447 ->notifier(boost::bind(&Player::setBaseUrl, &p, _1)),
448 _("Set \"base\" URL for resolving relative URLs"))
450 ("param,P", po::value<std::vector<std::string> >()
451 ->composing()
452 ->notifier(boost::bind(&setupFlashVars, boost::ref(p), _1)),
453 _("Set parameter (e.g. \"FlashVars=A=1&b=2\")"))
455 ("fd,F", po::value<string>()
456 ->notifier(boost::bind(&setupFDs, boost::ref(p), _1)),
457 (string(_("Filedescriptor to use for external communications"))
458 + string(" <fd>:<fd>")
459 ).c_str())
461 #ifdef GNASH_FPS_DEBUG
462 ("debug-fps,f", po::value<float>()
463 ->notifier(boost::bind(&Player::setFpsPrintTime, &p, _1)),
464 _("Print FPS every num seconds"))
465 #endif
467 ("max-advances", po::value<size_t>()
468 ->notifier(boost::bind(&Player::setMaxAdvances, &p, _1)),
469 _("Exit after specified number of frame advances"))
471 ("fullscreen", po::bool_switch()
472 ->notifier(boost::bind(&Player::setStartFullscreen, &p, _1)),
473 _("Start in fullscreen mode"))
475 // TODO: move to GUIs actually implementing this
476 ("hide-menubar", po::bool_switch()
477 ->notifier(boost::bind(&Player::hideMenu, &p, _1)),
478 _("Start without displaying the menu bar"))
480 // TODO: do this in ScreenShotter class.
481 ("screenshot", po::value<string>()
482 ->notifier(boost::bind(&Player::setScreenShots, &p, _1)),
483 _("List of frames to save as screenshots"))
485 ("screenshot-file", po::value<string>()
486 ->notifier(boost::bind(&Player::setScreenShotFile, &p, _1)),
487 _("Filename pattern for screenshot images"))
489 ("screenshot-quality", po::value<size_t>()
490 ->notifier(boost::bind(&Player::setScreenShotQuality, &p, _1)),
491 _("Quality for screenshot output (not all formats)"))
493 ("input-file", po::value<std::vector<std::string> >(&infiles),
494 _("Input files"))
497 return desc;
500 void
501 usage_gui_keys(std::ostream& os)
503 os << _("Keys:\n")
504 << " CTRL-Q, CTRL-W "
505 << _("Quit\n")
506 << " CTRL-F "
507 << _("Toggle fullscreen\n")
508 << " CTRL-P "
509 << _("Toggle pause\n")
510 << " CTRL-R "
511 << _("Restart the movie\n")
512 << " CTRL-O "
513 << _("Take a screenshot\n")
514 << " CTRL-L "
515 << _("Force immediate redraw\n");
518 void
519 usage(std::ostream& os, const po::options_description& opts)
521 os << _("Usage: gnash [options] movie_file.swf\n")
522 << _("Plays a SWF (Shockwave Flash) movie\n")
523 << opts << "\n";
525 // Add gui keys
526 // TODO: stop printing these in here ?
527 usage_gui_keys(os);
529 os << std::endl;
532 void
533 version_and_copyright(std::ostream& os)
535 os << "Gnash "
536 << VERSION " ("
537 << BRANCH_NICK << "-" << BRANCH_REVNO << "-" << COMMIT_ID
538 << ")" << endl << endl
539 << _("Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 "
540 "Free Software Foundation, Inc.\n"
541 "Gnash comes with NO WARRANTY, to the extent permitted "
542 "by law.\nYou may redistribute copies of Gnash under the "
543 "terms of the GNU General\nPublic License. For more "
544 "information, see the file named COPYING.\n\n");
547 void
548 build_options(std::ostream& os)
550 os << _("Build options ") << endl
551 << _(" Renderers: ") << RENDERER_CONFIG << endl
552 << _(" Hardware Acceleration: ") << HWACCEL_CONFIG << endl
553 << _(" GUI: ") << GUI_CONFIG << endl
554 << _(" Media handlers: ") << MEDIA_CONFIG << endl
556 << _(" Configured with: ") << CONFIG_CONFIG << endl
557 << _(" CXXFLAGS: ") << CXXFLAGS << endl;
561 } // unnamed namespace