add some Flash 9 types
[swfdec.git] / swfdec-gtk / swfdec_gtk_player.c
blob16dae783f131f287d8ec15725536c8a4a89f262c
1 /* Swfdec
2 * Copyright (C) 2007 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
24 #ifdef HAVE_GST
25 #include <gst/pbutils/pbutils.h>
26 #endif
28 #include <gtk/gtk.h>
29 #ifdef GDK_WINDOWING_X11
30 #include <gdk/gdkx.h>
31 #endif
33 #include "swfdec-gtk/swfdec_gtk_loader.h"
34 #include "swfdec-gtk/swfdec_gtk_player.h"
35 #include "swfdec-gtk/swfdec_gtk_socket.h"
36 #include "swfdec-gtk/swfdec_gtk_system.h"
37 #include "swfdec-gtk/swfdec_playback.h"
38 #include "swfdec-gtk/swfdec_source.h"
40 struct _SwfdecGtkPlayerPrivate
42 GSource * source; /* source if playing, NULL otherwise */
43 SwfdecPlayback * playback; /* audio playback object */
44 gboolean audio_enabled; /* TRUE if audio should be played */
45 double speed; /* desired playback speed */
47 /* missing plugins */
48 GdkWindow * missing_plugins_window; /* window used for displaying missing plugins info */
49 #ifdef HAVE_GST
50 GstInstallPluginsContext *missing_plugins_context; /* context used during install */
51 #endif
52 gboolean needs_resume; /* restart playback after plugin install is done? */
55 enum {
56 PROP_0,
57 PROP_PLAYING,
58 PROP_AUDIO,
59 PROP_SPEED,
60 PROP_MISSING_PLUGINS_WINDOW
63 /*** gtk-doc ***/
65 /**
66 * SECTION:SwfdecGtkPlayer
67 * @title: SwfdecGtkPlayer
68 * @short_description: an improved #SwfdecPlayer
70 * The #SwfdecGtkPlayer adds common functionality to the rather barebones
71 * #SwfdecPlayer class, such as automatic playback and audio handling. Note
72 * that by default, the player will be paused, so you need to call
73 * swfdec_gtk_player_set_playing () on the new player.
75 * @see_also: SwfdecPlayer
78 /**
79 * SwfdecGtkPlayer:
81 * The structure for the Swfdec Gtk player contains no public fields.
84 /**
85 * SWFDEC_GTK_PRIORITY_ITERATE:
87 * The priority used for advancing a player that is playing.
90 /**
91 * SWFDEC_GTK_PRIORITY_REDRAW:
93 * The priority used for scheduling repaint operations resulting from advancing
94 * a player.
97 /*** MISSING PLUGINS ***/
99 #ifdef HAVE_GST
100 static void
101 swfdec_gtk_player_missing_plugins_done (GstInstallPluginsReturn result, gpointer data)
103 SwfdecGtkPlayer *player = data;
104 SwfdecGtkPlayerPrivate *priv = player->priv;
106 gst_update_registry ();
107 if (priv->needs_resume)
108 swfdec_gtk_player_set_playing (player, TRUE);
110 #endif
112 static void
113 swfdec_gtk_player_missing_plugins (SwfdecPlayer *player, const char **details)
115 SwfdecGtkPlayerPrivate *priv = SWFDEC_GTK_PLAYER (player)->priv;
117 /* That should only happen if users don't listen and then we don't listen either */
118 #ifdef HAVE_GST
119 if (priv->missing_plugins_context)
120 return;
121 #endif
122 /* no automatic install desired */
123 if (priv->missing_plugins_window == NULL)
124 return;
126 #ifdef HAVE_GST
128 GstInstallPluginsReturn result;
129 priv->missing_plugins_context = gst_install_plugins_context_new ();
130 #ifdef GDK_WINDOWING_X11
131 gst_install_plugins_context_set_xid (priv->missing_plugins_context,
132 GDK_DRAWABLE_XID (priv->missing_plugins_window));
133 #endif
134 result = gst_install_plugins_async ((char **) details, priv->missing_plugins_context,
135 swfdec_gtk_player_missing_plugins_done, player);
136 if (result == GST_INSTALL_PLUGINS_STARTED_OK) {
137 if (swfdec_gtk_player_get_playing (SWFDEC_GTK_PLAYER (player))) {
138 swfdec_gtk_player_set_playing (SWFDEC_GTK_PLAYER (player), FALSE);
139 priv->needs_resume = TRUE;
141 } else {
142 /* FIXME: error handling */
145 #endif
148 /*** SWFDEC_GTK_PLAYER ***/
150 G_DEFINE_TYPE (SwfdecGtkPlayer, swfdec_gtk_player, SWFDEC_TYPE_PLAYER)
152 static void
153 swfdec_gtk_player_get_property (GObject *object, guint param_id, GValue *value,
154 GParamSpec * pspec)
156 SwfdecGtkPlayerPrivate *priv = SWFDEC_GTK_PLAYER (object)->priv;
158 switch (param_id) {
159 case PROP_PLAYING:
160 g_value_set_boolean (value, priv->source != NULL);
161 break;
162 case PROP_AUDIO:
163 g_value_set_boolean (value, priv->audio_enabled);
164 break;
165 case PROP_SPEED:
166 g_value_set_double (value, priv->speed);
167 break;
168 case PROP_MISSING_PLUGINS_WINDOW:
169 g_value_set_object (value, G_OBJECT (priv->missing_plugins_window));
170 break;
171 default:
172 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
173 break;
177 static void
178 swfdec_gtk_player_set_property (GObject *object, guint param_id, const GValue *value,
179 GParamSpec *pspec)
181 SwfdecGtkPlayer *player = SWFDEC_GTK_PLAYER (object);
183 switch (param_id) {
184 case PROP_PLAYING:
185 swfdec_gtk_player_set_playing (player, g_value_get_boolean (value));
186 break;
187 case PROP_AUDIO:
188 swfdec_gtk_player_set_audio_enabled (player, g_value_get_boolean (value));
189 break;
190 case PROP_SPEED:
191 swfdec_gtk_player_set_speed (player, g_value_get_double (value));
192 break;
193 case PROP_MISSING_PLUGINS_WINDOW:
194 swfdec_gtk_player_set_missing_plugins_window (player,
195 GDK_WINDOW (g_value_get_object (value)));
196 break;
197 default:
198 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
199 break;
203 static void
204 swfdec_gtk_player_dispose (GObject *object)
206 SwfdecGtkPlayer *player = SWFDEC_GTK_PLAYER (object);
208 swfdec_gtk_player_set_playing (player, FALSE);
209 swfdec_gtk_player_set_missing_plugins_window (player, NULL);
210 g_assert (player->priv->playback == NULL);
212 G_OBJECT_CLASS (swfdec_gtk_player_parent_class)->dispose (object);
215 static void
216 swfdec_gtk_player_class_init (SwfdecGtkPlayerClass * g_class)
218 GObjectClass *object_class = G_OBJECT_CLASS (g_class);
219 SwfdecPlayerClass *player_class = SWFDEC_PLAYER_CLASS (g_class);
221 g_type_class_add_private (g_class, sizeof (SwfdecGtkPlayerPrivate));
223 object_class->dispose = swfdec_gtk_player_dispose;
224 object_class->get_property = swfdec_gtk_player_get_property;
225 object_class->set_property = swfdec_gtk_player_set_property;
227 g_object_class_install_property (object_class, PROP_PLAYING,
228 g_param_spec_boolean ("playing", "playing", "TRUE if the player is playing (d'oh)",
229 FALSE, G_PARAM_READWRITE));
230 g_object_class_install_property (object_class, PROP_AUDIO,
231 g_param_spec_boolean ("audio-enabled", "audio enabled", "TRUE if automatic audio handling is enabled",
232 TRUE, G_PARAM_READWRITE));
233 g_object_class_install_property (object_class, PROP_SPEED,
234 g_param_spec_double ("speed", "speed", "desired playback speed",
235 G_MINDOUBLE, G_MAXDOUBLE, 1.0, G_PARAM_READWRITE));
236 g_object_class_install_property (object_class, PROP_MISSING_PLUGINS_WINDOW,
237 g_param_spec_object ("missing-plugins-window", "missing plugins window",
238 "window on which to do autmatic missing plugins installation",
239 GDK_TYPE_WINDOW, G_PARAM_READWRITE));
241 player_class->missing_plugins = swfdec_gtk_player_missing_plugins;
244 static void
245 swfdec_gtk_player_init (SwfdecGtkPlayer * player)
247 SwfdecGtkPlayerPrivate *priv;
249 player->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE (player, SWFDEC_TYPE_GTK_PLAYER, SwfdecGtkPlayerPrivate);
251 priv->speed = 1.0;
252 priv->audio_enabled = TRUE;
255 /*** PUBLIC API ***/
258 * swfdec_gtk_player_new:
259 * @debugger: %NULL or a #SwfdecAsDebugger to debug this player
261 * Creates a new Swfdec Gtk player.
262 * This function calls swfdec_init () for you if it wasn't called before.
264 * Returns: The new player
266 SwfdecPlayer *
267 swfdec_gtk_player_new (SwfdecAsDebugger *debugger)
269 SwfdecPlayer *player;
270 SwfdecSystem *sys;
272 swfdec_init ();
274 sys = swfdec_gtk_system_new (NULL);
275 player = g_object_new (SWFDEC_TYPE_GTK_PLAYER,
276 "loader-type", SWFDEC_TYPE_GTK_LOADER, "socket-type", SWFDEC_TYPE_GTK_SOCKET,
277 "system", sys, "debugger", debugger, NULL);
278 g_object_unref (sys);
280 return player;
283 static void
284 swfdec_gtk_player_update_audio (SwfdecGtkPlayer *player)
286 SwfdecGtkPlayerPrivate *priv = player->priv;
287 gboolean should_play = priv->audio_enabled;
289 should_play &= (priv->source != NULL);
290 should_play &= (priv->speed == 1.0);
292 if (should_play && priv->playback == NULL) {
293 priv->playback = swfdec_playback_open (SWFDEC_PLAYER (player),
294 g_main_context_default ());
295 } else if (!should_play && priv->playback != NULL) {
296 swfdec_playback_close (priv->playback);
297 priv->playback = NULL;
302 * swfdec_gtk_player_set_playing:
303 * @player: a #SwfdecGtkPlayer
304 * @playing: if the player should play or not
306 * Sets if @player should be playing or not. If the player is playing, a timer
307 * will be attached to the default main loop that periodically calls
308 * swfdec_player_advance().
310 void
311 swfdec_gtk_player_set_playing (SwfdecGtkPlayer *player, gboolean playing)
313 SwfdecGtkPlayerPrivate *priv;
315 g_return_if_fail (SWFDEC_IS_GTK_PLAYER (player));
317 priv = player->priv;
318 if (playing && priv->source == NULL) {
319 priv->source = swfdec_iterate_source_new (SWFDEC_PLAYER (player), priv->speed);
320 g_source_set_priority (priv->source, SWFDEC_GTK_PRIORITY_ITERATE);
321 g_source_attach (priv->source, NULL);
322 } else if (!playing && priv->source != NULL) {
323 g_source_destroy (priv->source);
324 g_source_unref (priv->source);
325 priv->source = NULL;
326 } else {
327 return;
329 priv->needs_resume = FALSE;
330 swfdec_gtk_player_update_audio (player);
331 g_object_notify (G_OBJECT (player), "playing");
335 * swfdec_gtk_player_get_playing:
336 * @player: a #SwfdecGtkPlayer
338 * Queries if the player is playing.
340 * Returns: %TRUE if the player is playing
342 gboolean
343 swfdec_gtk_player_get_playing (SwfdecGtkPlayer *player)
345 g_return_val_if_fail (SWFDEC_IS_GTK_PLAYER (player), FALSE);
347 return player->priv->source != NULL;
351 * swfdec_gtk_player_set_audio_enabled:
352 * @player: a #SwfdecGtkPlayer
353 * @enabled: %TRUE to enable audio
355 * Enables or disables automatic audio playback.
357 void
358 swfdec_gtk_player_set_audio_enabled (SwfdecGtkPlayer *player, gboolean enabled)
360 g_return_if_fail (SWFDEC_IS_GTK_PLAYER (player));
362 if (player->priv->audio_enabled == enabled)
363 return;
364 player->priv->audio_enabled = enabled;
365 swfdec_gtk_player_update_audio (player);
366 g_object_notify (G_OBJECT (player), "audio-enabled");
370 * swfdec_gtk_player_get_audio_enabled:
371 * @player: a #SwfdecGtkPlayer
373 * Queries if audio playback for @player is enabled or not.
375 * Returns: %TRUE if audio playback is enabled
377 gboolean
378 swfdec_gtk_player_get_audio_enabled (SwfdecGtkPlayer *player)
380 g_return_val_if_fail (SWFDEC_IS_GTK_PLAYER (player), FALSE);
382 return player->priv->audio_enabled;
386 * swfdec_gtk_player_set_speed:
387 * @player: a #SwfdecGtkPlayer
388 * @speed: the new playback speed
390 * Sets the new playback speed. 1.0 means the default speed, bigger values
391 * make playback happen faster. Audio will only play back if the speed is
392 * 1.0. Note that if the player is not playing when calling this function,
393 * it will not automatically start.
395 void
396 swfdec_gtk_player_set_speed (SwfdecGtkPlayer *player, double speed)
398 g_return_if_fail (SWFDEC_IS_GTK_PLAYER (player));
399 g_return_if_fail (speed > 0.0);
401 player->priv->speed = speed;
402 swfdec_gtk_player_update_audio (player);
403 if (player->priv->source)
404 swfdec_iterate_source_set_speed (player->priv->source, player->priv->speed);
405 g_object_notify (G_OBJECT (player), "speed");
409 * swfdec_gtk_player_get_speed:
410 * @player: a #SwfdecGtkPlayer
412 * Queries the current playback speed. If the player is currently paused, it
413 * will report the speed that it would use if playing.
415 * Returns: the current playback speed.
417 double
418 swfdec_gtk_player_get_speed (SwfdecGtkPlayer *player)
420 g_return_val_if_fail (SWFDEC_IS_GTK_PLAYER (player), FALSE);
422 return player->priv->speed;
426 * swfdec_gtk_player_set_missing_plugins_window:
427 * @player: a #SwfdecGtkPlayer
428 * @window: the window to use for popping up codec install dialogs or %NULL
430 * Sets a given #GdkWindow to be used as the reference window when popping up
431 * automatic codec install dialogs. Automatic codec install happens when Swfdec
432 * cannot find a GStreamer plugin to play back a given media file. The player
433 * will automaticcaly pause when this happens to allow the plugin install to
434 * finish and will resume playback after the codec install has completed.
435 * You can use %NULL to disable this feature. It is disable by default.
436 * Note that this function takes a #GdkWindow, not a #GtkWindow, as its
437 * argument. This makes it slightly more inconvenient to use, as you need to
438 * call gtk_widget_show() on your #GtkWindow before having access to its
439 * #GdkWindow, but it allows automatic plugin installatio even when your
440 * application does not have a window. You can use gdk_get_default_root_window()
441 * to obtain a default window in that case.
442 * For details about automatic codec install, see the GStreamer documentation,
443 * in particular the function gst_install_plugins_async(). If Swfdec was
444 * compiled without GStreamer support, this function will have no effect.
446 void
447 swfdec_gtk_player_set_missing_plugins_window (SwfdecGtkPlayer *player,
448 GdkWindow *window)
450 SwfdecGtkPlayerPrivate *priv;
452 g_return_if_fail (SWFDEC_IS_GTK_PLAYER (player));
453 g_return_if_fail (window == NULL || GDK_IS_WINDOW (window));
455 priv = player->priv;
456 if (priv->missing_plugins_window)
457 g_object_unref (priv->missing_plugins_window);
459 priv->missing_plugins_window = window;
461 if (window)
462 g_object_ref (window);
463 g_object_notify (G_OBJECT (player), "missing-plugins-window");
467 * swfdec_gtk_player_get_missing_plugins_window:
468 * @player: a #SwfdecPlayer
470 * Gets the window used for automatic codec install. See
471 * swfdec_gtk_player_set_missing_plugins_window() for details.
473 * Returns: the #GdkWindow used as parent for showing missing plugin dialogs or
474 * %NULL if automatic codec install is disabled.
476 GdkWindow *
477 swfdec_gtk_player_get_missing_plugins_window (SwfdecGtkPlayer *player)
479 g_return_val_if_fail (SWFDEC_IS_GTK_PLAYER (player), NULL);
481 return player->priv->missing_plugins_window;