properly exit when hitting a stack overflow (fixes #13491)
[swfdec.git] / player / swfplay.c
blob79978be2eb24a3ac705e33b1d15500a594c2b271
1 /* Swfdec
2 * Copyright (C) 2006 Benjamin Otte <otte@gnome.org>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301 USA
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23 #include <gtk/gtk.h>
24 #include <math.h>
25 #include <libswfdec/swfdec.h>
27 #include <libswfdec-gtk/swfdec-gtk.h>
29 #include "swfdec_slow_loader.h"
31 static GMainLoop *loop = NULL;
33 static void
34 set_title (GtkWindow *window, const char *filename)
36 char *name = g_filename_display_basename (filename);
37 char *title = g_strdup_printf ("%s : Swfplay", name);
39 g_free (name);
40 gtk_window_set_title (window, title);
41 g_free (title);
44 static GtkWidget *
45 view_swf (SwfdecPlayer *player, gboolean use_image)
47 GtkWidget *window, *widget;
49 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
50 gtk_window_set_icon_name (GTK_WINDOW (window), "swfdec");
51 widget = swfdec_gtk_widget_new (player);
52 if (use_image)
53 swfdec_gtk_widget_set_renderer (SWFDEC_GTK_WIDGET (widget), CAIRO_SURFACE_TYPE_IMAGE);
54 gtk_container_add (GTK_CONTAINER (window), widget);
55 g_signal_connect_swapped (window, "destroy", G_CALLBACK (g_main_loop_quit), loop);
56 gtk_widget_show_all (window);
58 return window;
61 static void
62 do_fscommand (SwfdecPlayer *player, const char *command, const char *value, gpointer window)
64 if (g_str_equal (command, "quit")) {
65 g_assert (loop);
66 if (g_main_loop_is_running (loop)) {
67 gtk_widget_destroy (window);
68 g_main_loop_quit (loop);
71 /* FIXME: add more */
74 static void
75 print_trace (SwfdecPlayer *player, const char *message, gpointer unused)
77 g_print ("%s\n", message);
80 static char *
81 sanitize_url (const char *s)
83 SwfdecURL *url;
85 url = swfdec_url_new (s);
86 if (g_str_equal (swfdec_url_get_protocol (url), "error")) {
87 char *dir, *full;
88 swfdec_url_free (url);
89 if (g_path_is_absolute (s))
90 return g_strconcat ("file://", s, NULL);
91 dir = g_get_current_dir ();
92 full = g_strconcat ("file://", dir, G_DIR_SEPARATOR_S, s, NULL);
93 g_free (dir);
94 return full;
95 } else {
96 swfdec_url_free (url);
97 return g_strdup (s);
101 int
102 main (int argc, char *argv[])
104 int delay = 0;
105 int speed = 100;
106 int max_runtime = 0;
107 SwfdecLoader *loader;
108 SwfdecPlayer *player;
109 GError *error = NULL;
110 gboolean use_image = FALSE, no_sound = FALSE;
111 gboolean trace = FALSE, no_scripts = FALSE;
112 gboolean redraws = FALSE, gc = FALSE;
113 char *variables = NULL;
114 char *s;
115 GtkWidget *window;
117 GOptionEntry options[] = {
118 { "always-gc", 'g', 0, G_OPTION_ARG_NONE, &gc, "run the garbage collector as often as possible", NULL },
119 { "delay", 'd', 0, G_OPTION_ARG_INT, &delay, "make loading of resources take time", "SECS" },
120 { "image", 'i', 0, G_OPTION_ARG_NONE, &use_image, "use an intermediate image surface for drawing", NULL },
121 { "max-runtime", 0, 0, G_OPTION_ARG_INT, &max_runtime, "maximum time scripts run before aborting the player", "SECS" },
122 { "no-scripts", 0, 0, G_OPTION_ARG_NONE, &no_scripts, "don't execute scripts affecting the application", NULL },
123 { "no-sound", 'n', 0, G_OPTION_ARG_NONE, &no_sound, "don't play sound", NULL },
124 { "redraws", 'r', 0, G_OPTION_ARG_NONE, &redraws, "show redraw regions", NULL },
125 { "speed", 0, 0, G_OPTION_ARG_INT, &speed, "replay speed (will deactivate sound)", "PERCENT" },
126 { "trace", 't', 0, G_OPTION_ARG_NONE, &trace, "print trace output to stdout", NULL },
127 { "variables", 'v', 0, G_OPTION_ARG_STRING, &variables, "variables to pass to player", "VAR=NAME[&VAR=NAME..]" },
128 { NULL }
130 GOptionContext *ctx;
132 ctx = g_option_context_new ("");
133 g_option_context_add_main_entries (ctx, options, "options");
134 g_option_context_add_group (ctx, gtk_get_option_group (TRUE));
135 g_option_context_parse (ctx, &argc, &argv, &error);
136 g_option_context_free (ctx);
138 if (error) {
139 g_printerr ("Error parsing command line arguments: %s\n", error->message);
140 g_error_free (error);
141 return 1;
144 swfdec_init ();
146 if (argc < 2) {
147 g_printerr ("Usage: %s [OPTIONS] filename\n", argv[0]);
148 return 1;
151 s = sanitize_url (argv[1]);
152 loader = swfdec_gtk_loader_new (s);
153 g_free (s);
154 if (loader->error) {
155 g_printerr ("Couldn't open file \"%s\": %s\n", argv[1], loader->error);
156 g_object_unref (loader);
157 return 1;
159 loop = g_main_loop_new (NULL, TRUE);
160 player = swfdec_gtk_player_new (NULL);
161 /* this allows the player to continue fine when running in gdb */
162 if (max_runtime >= 0)
163 swfdec_player_set_maximum_runtime (player, max_runtime * 1000);
164 if (gc)
165 g_object_set (player, "memory-until-gc", (gulong) 0, NULL);
166 if (trace)
167 g_signal_connect (player, "trace", G_CALLBACK (print_trace), NULL);
168 swfdec_gtk_player_set_speed (SWFDEC_GTK_PLAYER (player), speed / 100.);
170 if (no_sound)
171 swfdec_gtk_player_set_audio_enabled (SWFDEC_GTK_PLAYER (player), FALSE);
173 window = view_swf (player, use_image);
174 set_title (GTK_WINDOW (window), argv[1]);
175 if (redraws)
176 gdk_window_set_debug_updates (TRUE);
178 if (!no_scripts)
179 g_signal_connect (player, "fscommand", G_CALLBACK (do_fscommand), window);
181 if (delay)
182 loader = swfdec_slow_loader_new (loader, delay);
184 swfdec_player_set_loader_with_variables (player, loader, variables);
186 swfdec_gtk_player_set_playing (SWFDEC_GTK_PLAYER (player), TRUE);
188 if (g_main_loop_is_running (loop))
189 g_main_loop_run (loop);
191 g_object_unref (player);
192 g_main_loop_unref (loop);
193 loop = NULL;
194 player = NULL;
195 return 0;