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.
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
25 #include <gst/pbutils/pbutils.h>
29 #ifdef GDK_WINDOWING_X11
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 */
48 GdkWindow
* missing_plugins_window
; /* window used for displaying missing plugins info */
50 GstInstallPluginsContext
*missing_plugins_context
; /* context used during install */
52 gboolean needs_resume
; /* restart playback after plugin install is done? */
60 PROP_MISSING_PLUGINS_WINDOW
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
81 * The structure for the Swfdec Gtk player contains no public fields.
85 * SWFDEC_GTK_PRIORITY_ITERATE:
87 * The priority used for advancing a player that is playing.
91 * SWFDEC_GTK_PRIORITY_REDRAW:
93 * The priority used for scheduling repaint operations resulting from advancing
97 /*** MISSING PLUGINS ***/
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
);
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 */
119 if (priv
->missing_plugins_context
)
122 /* no automatic install desired */
123 if (priv
->missing_plugins_window
== NULL
)
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
));
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
;
142 /* FIXME: error handling */
148 /*** SWFDEC_GTK_PLAYER ***/
150 G_DEFINE_TYPE (SwfdecGtkPlayer
, swfdec_gtk_player
, SWFDEC_TYPE_PLAYER
)
153 swfdec_gtk_player_get_property (GObject
*object
, guint param_id
, GValue
*value
,
156 SwfdecGtkPlayerPrivate
*priv
= SWFDEC_GTK_PLAYER (object
)->priv
;
160 g_value_set_boolean (value
, priv
->source
!= NULL
);
163 g_value_set_boolean (value
, priv
->audio_enabled
);
166 g_value_set_double (value
, priv
->speed
);
168 case PROP_MISSING_PLUGINS_WINDOW
:
169 g_value_set_object (value
, G_OBJECT (priv
->missing_plugins_window
));
172 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, param_id
, pspec
);
178 swfdec_gtk_player_set_property (GObject
*object
, guint param_id
, const GValue
*value
,
181 SwfdecGtkPlayer
*player
= SWFDEC_GTK_PLAYER (object
);
185 swfdec_gtk_player_set_playing (player
, g_value_get_boolean (value
));
188 swfdec_gtk_player_set_audio_enabled (player
, g_value_get_boolean (value
));
191 swfdec_gtk_player_set_speed (player
, g_value_get_double (value
));
193 case PROP_MISSING_PLUGINS_WINDOW
:
194 swfdec_gtk_player_set_missing_plugins_window (player
,
195 GDK_WINDOW (g_value_get_object (value
)));
198 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, param_id
, pspec
);
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
);
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
;
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
);
252 priv
->audio_enabled
= TRUE
;
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
267 swfdec_gtk_player_new (SwfdecAsDebugger
*debugger
)
269 SwfdecPlayer
*player
;
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
);
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().
311 swfdec_gtk_player_set_playing (SwfdecGtkPlayer
*player
, gboolean playing
)
313 SwfdecGtkPlayerPrivate
*priv
;
315 g_return_if_fail (SWFDEC_IS_GTK_PLAYER (player
));
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
);
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
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.
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
)
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
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.
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.
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.
447 swfdec_gtk_player_set_missing_plugins_window (SwfdecGtkPlayer
*player
,
450 SwfdecGtkPlayerPrivate
*priv
;
452 g_return_if_fail (SWFDEC_IS_GTK_PLAYER (player
));
453 g_return_if_fail (window
== NULL
|| GDK_IS_WINDOW (window
));
456 if (priv
->missing_plugins_window
)
457 g_object_unref (priv
->missing_plugins_window
);
459 priv
->missing_plugins_window
= 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.
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
;