/* GStreamer
* Copyright (C) 1999,2000,2001,2002 Erik Walthinsen <omega@cse.ogi.edu>
* 2000,2001,2002 Wim Taymans <wtay@chello.be>
* 2002 Steve Baker <steve@stevebaker.org>
* 2003 Julien Moutte <julien@moutte.net>
*
* gstmediaplay.c: Media Player widget for Gst-Player
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <locale.h>
/* Gnome stuff */
#include <gnome.h>
#include <libgnomevfs/gnome-vfs.h>
#include <gconf/gconf-client.h>
#include <glade/glade.h>
/* GStreamer Interfaces */
#include <gst/xoverlay/xoverlay.h>
#include <gst/navigation/navigation.h>
#include <gst/mixer/mixer.h>
#include <gst/gconf/gconf.h>
#include "gstmediaplay.h"
#include "gstvideowidget.h"
#include "gstpreferences.h"
#include "gstmediainfo.h"
#include "gstcontrol.h"
#include "gstplayer-marshal.h"
#include "gtk-playlist.h"
struct _GstMediaPlayPrivate
{
GladeXML *media_info_xml;
GstPlay *play;
GstMixer *mixer;
GstMixerTrack *mixer_track;
GstXOverlay *xoverlay;
GdkWindow *video_window;
gint video_window_x;
gint video_window_y;
gint video_window_w;
gint video_window_h;
GtkWidget *video_widget;
GtkWidget *control;
GtkWidget *media_info;
GtkWindow *control_fs_window;
GtkVBox *control_fs_vbox;
GdkPixbuf *logo_pixbuf;
GdkPixbuf *play_pixbuf;
const char *location;
const char *location_short;
gboolean auto_resize;
gboolean media_has_video;
gboolean with_visualization;
char *vis_plugin_name;
GstElement *vis_element;
GstMediaPlayMode display_mode;
gboolean fs_control_bar_visible;
gint64 length_nanos;
gint64 current_time_nanos;
/* For moving the control window */
guint32 move_id;
guint32 hide_cursor_id;
int control_y;
/* for housekeeping if ui has been touched since last error */
gboolean ui_touched;
GAsyncQueue *queue;
};
enum
{
VIDEO_SIZE,
STATE,
ERROR,
FOUND_TAG
};
typedef struct _GstMediaPlaySignal GstMediaPlaySignal;
struct _GstMediaPlaySignal
{
gint signal_id;
union
{
struct
{
gint width;
gint height;
} video_size;
struct
{
GstElementState old_state;
GstElementState new_state;
} state;
struct
{
GstElement *element;
GError *error;
gchar *debug;
} error;
struct
{
GstElement *source;
GstTagList *tag_list;
} found_tag;
} signal_data;
};
static const GtkTargetEntry target_table[] = {
{"text/uri-list", 0, 0},
};
static GtkVBoxClass *parent_class = NULL;
enum
{
STATE_CHANGE,
DISPLAY_MODE_CHANGE,
CURRENT_LOCATION,
PLAYBACK_ERROR,
LAST_SIGNAL
};
static gint gst_media_play_signals[LAST_SIGNAL] = { 0 };
/* ============================================================= */
/* */
/* Private Methods */
/* */
/* ============================================================= */
/* =========================================== */
/* */
/* Tool Box */
/* */
/* =========================================== */
GQuark
gst_media_play_error_quark (void)
{
static GQuark quark = 0;
if (quark == 0)
quark = g_quark_from_static_string ("gst-media-play-error-quark");
return quark;
}
static GladeXML *
gst_media_play_get_glade_xml_from_file (const gchar * fname,
const gchar * root, const gchar * domain, gboolean connect_signals)
{
GladeXML *xml;
xml = glade_xml_new (fname, root, domain);
if (connect_signals) {
/* connect the signals in the interface */
glade_xml_signal_autoconnect (xml);
}
return xml;
}
static GladeXML *
gst_media_play_get_glade_xml (const gchar * fname,
const gchar * root, const gchar * domain, gboolean connect_signals)
{
gchar *full_fname = NULL;
GladeXML *xml = NULL;
full_fname = gst_media_play_get_ui_file (fname);
g_return_val_if_fail (full_fname != NULL, NULL);
xml = gst_media_play_get_glade_xml_from_file (full_fname,
root, domain, connect_signals);
if (full_fname)
g_free (full_fname);
return xml;
}
static void
gst_media_error_dialog (GError * error, const gchar * debug)
{
GtkWidget *dialog;
/* throw up a dialog box; FIXME: we don't have a parent */
/* FIXME: maybe even fallback the GError and do error
* handling higher up ? */
g_assert (error);
dialog = gtk_message_dialog_new (NULL, 0,
GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, error->message);
g_signal_connect_swapped (GTK_OBJECT (dialog), "response",
G_CALLBACK (gtk_widget_destroy), GTK_OBJECT (dialog));
gtk_dialog_run (GTK_DIALOG (dialog));
g_error_free (error);
}
static void
gst_media_play_update_interfaces (GstMediaPlay * mplay)
{
g_return_if_fail (GST_IS_MEDIA_PLAY (mplay));
/* We try to get interesting elements from the GstPlay bin through the
interfaces they implement */
if (GST_IS_BIN (mplay->_priv->play)) {
GstElement *element = NULL;
GList *elements = NULL, *l_elements = NULL;
/* First let's search for an XOverlay */
element = gst_bin_get_by_interface (GST_BIN (mplay->_priv->play),
GST_TYPE_X_OVERLAY);
if (GST_IS_X_OVERLAY (element))
mplay->_priv->xoverlay = GST_X_OVERLAY (element);
/* If we found one we tell it to use our video window */
if (GST_IS_X_OVERLAY (mplay->_priv->xoverlay) &&
GDK_IS_WINDOW (mplay->_priv->video_window))
gst_x_overlay_set_xwindow_id (mplay->_priv->xoverlay,
GDK_WINDOW_XID (mplay->_priv->video_window));
/* Now search for a volume mixer and prefer a software interface */
/* Get them all and prefer software one */
elements = gst_bin_get_all_by_interface (GST_BIN (mplay->_priv->play),
GST_TYPE_MIXER);
l_elements = elements;
/* We take the first one */
if (elements && GST_IS_MIXER (elements->data))
element = GST_ELEMENT (elements->data);
while (elements) {
GstElement *local_element = NULL;
GstMixerClass *m_class = NULL;
if (elements->data && GST_IS_MIXER (elements->data)) {
local_element = GST_ELEMENT (elements->data);
m_class = GST_MIXER_GET_CLASS (elements->data);
/* If one of them is hardware type we use that one then */
if (GST_MIXER_TYPE (m_class) == GST_MIXER_SOFTWARE) {
element = local_element;
}
}
elements = g_list_next (elements);
}
if (l_elements)
g_list_free (l_elements);
elements = l_elements = NULL;
if (GST_IS_MIXER (element)) {
const GList *tracks;
mplay->_priv->mixer = GST_MIXER (element);
tracks = gst_mixer_list_tracks (GST_MIXER (element));
if (tracks)
mplay->_priv->mixer_track = GST_MIXER_TRACK (tracks->data);
} else
g_warning ("can't find any mixer element, no volume.");
}
}
/* =========================================== */
/* */
/* GFX stuff */
/* */
/* =========================================== */
static void
gst_media_play_toggle_playlist (Gtk