[Xfce4-commits] <parole:master> Expose media plugin dbus method to shutdown the plugin cleanly.

Ali Abdallah noreply at xfce.org
Tue Nov 17 11:48:02 CET 2009


Updating branch refs/heads/master
         to 8d0543c88805348e4b188908bebd771211679ff6 (commit)
       from 0f31192ff9b250c21e1f8b59ba5f9081fdfb6370 (commit)

commit 8d0543c88805348e4b188908bebd771211679ff6
Author: Ali Abdallah <ali at ali-xfce.org>
Date:   Tue Nov 17 11:46:12 2009 +0100

    Expose media plugin dbus method to shutdown the plugin cleanly.

 Makefile.am                                        |    1 +
 browser-plugin/Makefile.am                         |    6 +-
 browser-plugin/media-plugin/Makefile.am            |   24 +-
 browser-plugin/media-plugin/main.c                 |   14 +-
 .../media-plugin/org.parole.media.plugin.xml       |   13 +
 browser-plugin/media-plugin/parole-gst.c           |  389 +++++++++++++++++++-
 browser-plugin/media-plugin/parole-gst.h           |    2 +
 browser-plugin/parole-plugin.cpp                   |   28 ++
 browser-plugin/parole-plugin.h                     |   10 +-
 common/Makefile.am                                 |    9 +
 {parole => common}/parole-dbus.c                   |    0
 {parole => common}/parole-dbus.h                   |    0
 configure.ac.in                                    |    1 +
 data/interfaces/browser-plugin-control.ui          |   37 ++
 parole/Makefile.am                                 |    4 +-
 parole/parole-gst.c                                |    4 +-
 16 files changed, 523 insertions(+), 19 deletions(-)

diff --git a/Makefile.am b/Makefile.am
index 56530ba..8ab26c5 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -4,6 +4,7 @@ endif
 
 SUBDIRS =  			\
 	data			\
+	common			\
 	parole 			\
 	plugins			\
 	$(browser_plugin_dir)  	\
diff --git a/browser-plugin/Makefile.am b/browser-plugin/Makefile.am
index d058c90..f4fa674 100644
--- a/browser-plugin/Makefile.am
+++ b/browser-plugin/Makefile.am
@@ -8,7 +8,8 @@ INCLUDES = 						\
 	-DPACKAGE_LOCALE_DIR=\"$(localedir)\"		\
         -DG_LOG_DOMAIN=\"parole-browser-plugin\"	\
 	-DLIBEXECDIR="\"$(libexecdir)\""		\
-	$(GTK_CFLAGS)
+	$(GTK_CFLAGS)					\
+	$(DBUS_GLIB_CFLAGS)
 
 plugindir = $(BROWSER_PLUGIN_DIR)
 
@@ -33,7 +34,8 @@ parole_player_la_CPPFLAGS =				\
 	-I$(top_srcdir)/browser-plugin
 
 parole_player_la_LIBADD =				\
-	$(GTK_LIBS)
+	$(GTK_LIBS)					\
+	$(DBUS_GLIB_LIBS)
 
 parole_player_la_LDFLAGS =				\
 	-avoid-version  				\
diff --git a/browser-plugin/media-plugin/Makefile.am b/browser-plugin/media-plugin/Makefile.am
index 1efafbd..513d437 100644
--- a/browser-plugin/media-plugin/Makefile.am
+++ b/browser-plugin/media-plugin/Makefile.am
@@ -3,21 +3,39 @@ libexec_PROGRAMS = parole-media-plugin
 parole_media_plugin_SOURCES =			\
 	main.c					\
 	parole-gst.c				\
-	parole-gst.h
+	parole-gst.h				\
+	org.parole.media.plugin.h
 
 parole_media_plugin_CFLAGS =			\
 	-I$(top_srcdir)                         \
         -I$(top_srcdir)/data                    \
         -I$(top_srcdir)/data/mime               \
+	-I$(top_srcdir)/common               	\
         -DLOCALEDIR=\"$(localedir)\"            \
         -DG_LOG_DOMAIN=\"parole-media-plugin\"  \
 	$(GTHREAD_CFLAGS)                       \
 	$(GTK_CFLAGS)				\
 	$(GST_VIDEO_CFLAGS)                     \
-        $(GST_INTERFACES_CFLAGS)
+        $(GST_INTERFACES_CFLAGS)		\
+	$(DBUS_GLIB_CFLAGS)
 
 parole_media_plugin_LDADD =			\
+	$(top_builddir)/common/libparoledbus.la \
 	$(GTHREAD_LIBS)                       	\
 	$(GTK_LIBS)				\
 	$(GST_VIDEO_LIBS)                     	\
-        $(GST_INTERFACES_LIBS)
\ No newline at end of file
+        $(GST_INTERFACES_LIBS)			\
+	$(DBUS_GLIB_LIBS)
+
+if MAINTAINER_MODE
+
+BUILT_SOURCES =                                 \
+        org.parole.media.plugin.h
+
+org.parole.media.plugin.h: $(srcdir)/org.parole.media.plugin.xml
+	dbus-binding-tool --mode=glib-server --prefix=parole_gst $< >$@
+
+endif
+
+DISTCLEANFILES =				\
+	$(BUILT_SOURCES)
\ No newline at end of file
diff --git a/browser-plugin/media-plugin/main.c b/browser-plugin/media-plugin/main.c
index f25868f..4039cdc 100644
--- a/browser-plugin/media-plugin/main.c
+++ b/browser-plugin/media-plugin/main.c
@@ -92,19 +92,29 @@ int main (int argc, char **argv)
     g_option_context_free (ctx);
     
     {
+	GtkWidget *box;
 	GtkWidget *plug;
 	GtkWidget *gst;
+	
 	gulong sig_id;
 	plug = gtk_plug_new (socket_id);
 	
+	box = gtk_vbox_new (FALSE, 0);
+	
 	gst = parole_gst_new ();
 	
-	gtk_container_add (GTK_CONTAINER (plug), gst);
+	gtk_box_pack_start (GTK_BOX (box), gst, TRUE, TRUE, 0);
+	gtk_box_pack_start (GTK_BOX (box), parole_gst_get_controls (PAROLE_GST (gst)), 
+			    FALSE, FALSE, 0);
+	
+	gtk_container_add (GTK_CONTAINER (plug), box);
 	
 	sig_id = g_signal_connect (plug, "delete-event",
 				   G_CALLBACK (parole_terminate), gst);
-	parole_gst_play_url (PAROLE_GST (gst), url);
+				   
 	gtk_widget_show_all (plug);
+	parole_gst_play_url (PAROLE_GST (gst), url);
+	
 	gtk_main ();
 	g_signal_handler_disconnect (plug, sig_id);
 	gtk_widget_destroy (plug);
diff --git a/browser-plugin/media-plugin/org.parole.media.plugin.xml b/browser-plugin/media-plugin/org.parole.media.plugin.xml
new file mode 100644
index 0000000..0506de9
--- /dev/null
+++ b/browser-plugin/media-plugin/org.parole.media.plugin.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<node name="/">
+    <interface name="org.Parole.Media.Plugin">
+        <annotation name="org.freedesktop.DBus.GLib.CSymbol"
+                    value="parole_gst_dbus"/>
+
+    <method name="Quit">
+    </method>
+    
+    
+    </interface>
+</node>
diff --git a/browser-plugin/media-plugin/parole-gst.c b/browser-plugin/media-plugin/parole-gst.c
index 459d6ff..e308e50 100644
--- a/browser-plugin/media-plugin/parole-gst.c
+++ b/browser-plugin/media-plugin/parole-gst.c
@@ -33,8 +33,19 @@
 
 #include <gdk/gdkx.h>
 
+#include <dbus/dbus-glib.h>
+
 #include "parole-gst.h"
 
+#include "interfaces/browser-plugin-control_ui.h"
+#include "common/parole-dbus.h"
+
+/*
+ * DBus Glib init
+ */
+static void parole_gst_dbus_class_init (ParoleGstClass *klass);
+static void parole_gst_dbus_init       (ParoleGst *gst);
+
 static void parole_gst_finalize   (GObject *object);
 
 #define PAROLE_GST_GET_PRIVATE(o) \
@@ -49,30 +60,297 @@ struct ParoleGstPrivate
     GstState      state;
     GstState      target;
     
+    GtkWidget	 *controls;
+    GtkWidget	 *play;
+    GtkWidget	 *range;
+    
     gulong	  sig1;
     gulong	  sig2;
+    gulong	  tick_id;
     
     gboolean	  terminate;
-    
+    gboolean      internal_range_change;
+    gboolean      user_seeking;
+
+    /* Stream properties*/
     gboolean	  has_video;
+    gboolean      has_audio;
     gboolean	  buffering;
+    gboolean      live;
+    gboolean      seekable;
+    gdouble   	  duration;
+    gint64  	  absolute_duration;
+    
 };
 
 G_DEFINE_TYPE (ParoleGst, parole_gst, GTK_TYPE_WIDGET)
 
+static void parole_gst_seek (ParoleGst *gst, gdouble pos)
+{
+    gint64 seek;
+    
+    seek = (gint64) (pos * gst->priv->absolute_duration) / gst->priv->duration;
+    
+    g_debug ("seeking %lld", seek);
+    
+    g_warn_if_fail ( gst_element_seek (gst->priv->playbin,
+				       1.0,
+				       GST_FORMAT_TIME,
+				       GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT,
+				       GST_SEEK_TYPE_SET, seek,
+				       GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE));
+				       
+    gst_element_get_state (gst->priv->playbin, NULL, NULL, 100 * GST_MSECOND);
+}
+
+static void
+parole_gst_range_value_changed (GtkRange *range, ParoleGst *gst)
+{
+    gdouble value;
+    
+    if ( !gst->priv->internal_range_change )
+    {
+	value = gtk_range_get_value (GTK_RANGE (range));
+	gst->priv->user_seeking = TRUE;
+	parole_gst_seek (gst, value);
+	gst->priv->user_seeking = FALSE;
+    }
+}
+
+static gboolean
+parole_gst_range_button_release (GtkWidget *widget, GdkEventButton *ev, ParoleGst *gst)
+{
+    ev->button = 2;
+    
+    gst->priv->user_seeking = FALSE;
+    
+    return FALSE;
+}
+
+static gboolean
+parole_gst_range_button_press (GtkWidget *widget, GdkEventButton *ev, ParoleGst *gst)
+{
+    ev->button = 2;
+    
+    gst->priv->user_seeking = TRUE;
+    
+    return FALSE;
+}
+
+static void
+parole_gst_change_range_value (ParoleGst *gst, gdouble value)
+{
+    if ( !gst->priv->user_seeking )
+    {
+	gst->priv->internal_range_change = TRUE;
+    
+	gtk_range_set_value (GTK_RANGE (gst->priv->range), value);
+
+	gst->priv->internal_range_change = FALSE;
+    }
+}
+
+static void
+parole_gst_init_stream_properties (ParoleGst *gst)
+{
+    gst->priv->has_video = FALSE;
+    gst->priv->has_audio = FALSE;
+    gst->priv->buffering = FALSE;
+    gst->priv->duration  = 0;
+    gst->priv->absolute_duration = 0;
+    gst->priv->seekable = FALSE;
+    gst->priv->live = FALSE;
+    
+    gst->priv->user_seeking = FALSE;
+    
+    parole_gst_change_range_value (gst, 0);
+    gtk_widget_set_sensitive (gst->priv->range, FALSE);
+    gst->priv->internal_range_change = FALSE;
+}
+
+static gboolean
+parole_gst_tick_timeout (gpointer data)
+{
+    ParoleGst *gst;
+    
+    gint64 pos;
+    GstFormat format = GST_FORMAT_TIME;
+    gdouble value;
+    
+    gst = PAROLE_GST (data);
+    
+    gst_element_query_position (gst->priv->playbin, &format, &pos);
+    
+    if ( G_UNLIKELY (format != GST_FORMAT_TIME ) )
+	goto out;
+
+    if ( gst->priv->live )
+    {
+	gst->priv->tick_id = 0;
+	return FALSE;
+    }
+
+    if ( gst->priv->state == GST_STATE_PLAYING )
+    {
+	value = ( pos / ((gdouble) 60 * 1000 * 1000 * 1000 ));
+	parole_gst_change_range_value (gst, value);
+    }
+
+out:
+    return TRUE;
+}
+
+static void
+parole_gst_tick (ParoleGst *gst)
+{
+    if ( gst->priv->state >= GST_STATE_PAUSED )
+    {
+	if ( gst->priv->tick_id != 0 )
+	{
+	    return;
+	}
+	gst->priv->tick_id = g_timeout_add (1000, (GSourceFunc) parole_gst_tick_timeout, gst);
+    }
+    else if ( gst->priv->tick_id != 0)
+    {
+        g_source_remove (gst->priv->tick_id);
+	gst->priv->tick_id = 0;
+    }
+}
+
+static void
+parole_gst_set_play_button_image (ParoleGst *gst)
+{
+    GtkWidget *img;
+    
+    g_object_get (G_OBJECT (gst->priv->play),
+                  "image", &img,
+                  NULL);
+
+    if ( gst->priv->state == GST_STATE_PLAYING )
+    {
+        g_object_set (G_OBJECT (img),
+                      "stock", GTK_STOCK_MEDIA_PAUSE,
+                      NULL);
+    }
+    else
+    {
+        g_object_set (G_OBJECT (img),
+                      "stock", GTK_STOCK_MEDIA_PLAY,
+                      NULL);
+                      
+    }
+    g_object_unref (img);
+}
+
+static void
+parole_gst_query_capabilities (ParoleGst *gst)
+{
+    GstQuery *query;
+    
+    query = gst_query_new_seeking (GST_FORMAT_TIME);
+    
+    if ( gst_element_query (gst->priv->playbin, query) )
+    {
+	gst_query_parse_seeking (query,
+				 NULL,
+				 &gst->priv->seekable,
+				 NULL,
+				 NULL);
+				 
+	gtk_widget_set_sensitive (gst->priv->range, gst->priv->seekable);
+    }
+    gst_query_unref (query);
+}
+
+static void
+parole_gst_query_info (ParoleGst *gst)
+{
+    const GList *info = NULL;
+    GObject *obj;
+    GEnumValue *val;
+    GParamSpec *pspec;
+    gint type;
+    
+    g_object_get (G_OBJECT (gst->priv->playbin),
+		  "stream-info", &info,
+		  NULL);
+		  
+    for ( ; info != NULL; info = info->next )
+    {
+	obj = info->data;
+	
+	g_object_get (obj,
+		      "type", &type,
+		      NULL);
+	
+	pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (obj), "type");
+	val = g_enum_get_value (G_PARAM_SPEC_ENUM (pspec)->enum_class, type);
+	
+	if ( g_ascii_strcasecmp (val->value_name, "video") == 0 ||
+	     g_ascii_strcasecmp (val->value_nick, "video") == 0)
+	{
+	    gst->priv->has_video = TRUE;
+	}
+	if ( g_ascii_strcasecmp (val->value_name, "audio") == 0 ||
+	     g_ascii_strcasecmp (val->value_nick, "audio") == 0)
+	{
+	    gst->priv->has_video = TRUE;
+	}
+    }
+}
+
+static void
+parole_gst_query_duration (ParoleGst *gst)
+{
+    GstFormat gst_time;
+    
+    gst_time = GST_FORMAT_TIME;
+    
+    gst_element_query_duration (gst->priv->playbin, 
+				&gst_time,
+				&gst->priv->absolute_duration);
+    
+    if (gst_time == GST_FORMAT_TIME)
+    {
+	gst->priv->duration =  gst->priv->absolute_duration / ((gdouble) 60 * 1000 * 1000 * 1000);
+	gst->priv->live = ( gst->priv->absolute_duration == 0 );
+	
+	g_debug ("Stream duration=%f absolution_duration=%lld",  
+		 gst->priv->duration ,  gst->priv->absolute_duration);
+		 
+	if ( !gst->priv->live )
+	{
+	    gst->priv->internal_range_change = TRUE;
+	    gtk_range_set_range (GTK_RANGE (gst->priv->range), 0, gst->priv->duration);
+	    gst->priv->internal_range_change = FALSE;
+	}
+    }
+}
+
 static void
 parole_gst_evaluate_state (ParoleGst *gst, GstState old, GstState new, GstState pending)
 {
     gst->priv->state = new;
+    
+    parole_gst_set_play_button_image (gst);
+    parole_gst_tick (gst);
 
     switch (gst->priv->state)
     {
 	case GST_STATE_PLAYING:
 	    break;
 	case GST_STATE_PAUSED:
+	    if ( old == GST_STATE_READY )
+	    {
+		parole_gst_query_duration (gst);
+		parole_gst_query_capabilities (gst);
+		parole_gst_query_info (gst);
+	    }
 	    break;
 	case GST_STATE_READY:
 	    gst->priv->buffering = FALSE;
+	    break;
 	case GST_STATE_NULL:
 	    gst->priv->buffering = FALSE;
 	    if ( gst->priv->terminate )
@@ -155,7 +433,6 @@ parole_gst_bus_event (GstBus *bus, GstMessage *msg, gpointer data)
 	}
 	case GST_MESSAGE_ERROR:
 	{
-	    /*
 	    GError *error = NULL;
 	    gchar *debug;
 	    
@@ -163,11 +440,10 @@ parole_gst_bus_event (GstBus *bus, GstMessage *msg, gpointer data)
 	    gst->priv->buffering = FALSE;
 	    parole_gst_change_state (gst, GST_STATE_NULL);
 	    gst_message_parse_error (msg, &error, &debug);
-	    TRACE ("*** ERROR %s : %s ***", error->message, debug);
+	    g_critical ("*** ERROR %s : %s ***", error->message, debug);
 	    g_error_free (error);
 	    g_free (debug);
 	    gtk_widget_queue_draw (GTK_WIDGET (gst));
-	    */
 	    break;
 	}
 	case GST_MESSAGE_BUFFERING:
@@ -175,17 +451,20 @@ parole_gst_bus_event (GstBus *bus, GstMessage *msg, gpointer data)
 	    gint per = 0;
 	    gst_message_parse_buffering (msg, &per);
 	    gst->priv->buffering = per != 100;
+	    if ( per != 100 && gst->priv->state != GST_STATE_PAUSED)
+		parole_gst_change_state (gst, GST_STATE_PAUSED);
+	    else if ( gst->priv->state != GST_STATE_PLAYING)
+		parole_gst_change_state (gst, GST_STATE_PLAYING);
+		
 	    break;
 	}
 	case GST_MESSAGE_STATE_CHANGED:
 	{
-	    /*
 	    GstState old, new, pending;
 	    gst_message_parse_state_changed (msg, &old, &new, &pending);
 	    
 	    if ( GST_MESSAGE_SRC (msg) == GST_OBJECT (gst->priv->playbin) )
 		parole_gst_evaluate_state (gst, old, new, pending);
-	    */
 	    break;
 	}
 	case GST_MESSAGE_APPLICATION:
@@ -201,6 +480,15 @@ parole_gst_bus_event (GstBus *bus, GstMessage *msg, gpointer data)
 }
 
 static void
+parole_gst_play_clicked_cb (ParoleGst *gst)
+{
+    if ( gst->priv->state == GST_STATE_PLAYING )
+	parole_gst_change_state (gst, GST_STATE_PAUSED);
+    else
+	parole_gst_change_state (gst, GST_STATE_PLAYING);
+}
+
+static void
 parole_gst_construct (GObject *object)
 {
     ParoleGst *gst;
@@ -347,18 +635,57 @@ parole_gst_class_init (ParoleGstClass *klass)
     widget_class->expose_event = parole_gst_expose_event;
 
     g_type_class_add_private (klass, sizeof (ParoleGstPrivate));
+    
+    parole_gst_dbus_class_init (klass);
 }
 
 static void
 parole_gst_init (ParoleGst *gst)
 {
+    GtkBuilder *builder;
+    GError *error = NULL;
+    
     gst->priv = PAROLE_GST_GET_PRIVATE (gst);
     
+    parole_dbus_register_name ("org.Parole.Media.Plugin");
+    
     gst->priv->state = GST_STATE_VOID_PENDING;
     gst->priv->target = GST_STATE_VOID_PENDING;
     
+    gst->priv->tick_id = 0;
+    
     gst->priv->terminate = FALSE;
     
+    builder = gtk_builder_new ();
+    gtk_builder_add_from_string (builder, 
+				 browser_plugin_control_ui, 
+				 browser_plugin_control_ui_length,
+				 &error);
+				 
+    if ( error )
+    {
+	g_error ("%s", error->message);
+    }
+    
+    gst->priv->controls = GTK_WIDGET (gtk_builder_get_object (builder, "controls"));
+    
+    gst->priv->range = GTK_WIDGET (gtk_builder_get_object (builder, "scale"));
+    
+    gst->priv->play = GTK_WIDGET (gtk_builder_get_object (builder, "play"));
+    
+    g_signal_connect_swapped (gst->priv->play, "clicked",
+			      G_CALLBACK (parole_gst_play_clicked_cb), gst);
+
+    g_signal_connect (gst->priv->range, "button-press-event",
+		      G_CALLBACK (parole_gst_range_button_press), gst);
+
+    g_signal_connect (gst->priv->range, "button-release-event",
+		      G_CALLBACK (parole_gst_range_button_release), gst);
+		      
+    g_signal_connect (gst->priv->range, "value-changed",
+		      G_CALLBACK (parole_gst_range_value_changed), gst);
+
+    parole_gst_init_stream_properties (gst);
     
     GTK_WIDGET_SET_FLAGS (GTK_WIDGET (gst), GTK_CAN_FOCUS);
     
@@ -367,6 +694,8 @@ parole_gst_init (ParoleGst *gst)
      * flickering when resizing the window.
      */
     GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (gst), GTK_DOUBLE_BUFFERED);
+    
+    parole_gst_dbus_init (gst);
 }
 
 static void
@@ -375,7 +704,13 @@ parole_gst_finalize (GObject *object)
     ParoleGst *gst;
 
     gst = PAROLE_GST (object);
+    
+    parole_dbus_release_name ("org.Parole.Media.Plugin");
+    
     g_object_unref (gst->priv->playbin);
+    
+    if ( gst->priv->tick_id != 0)
+	g_source_remove (gst->priv->tick_id);
 
     G_OBJECT_CLASS (parole_gst_parent_class)->finalize (object);
 }
@@ -395,6 +730,7 @@ void parole_gst_play_url (ParoleGst *gst, const gchar *url)
     g_object_set (G_OBJECT (gst->priv->playbin),
 		  "uri", url,
 		  NULL);
+    gst->priv->target = GST_STATE_PLAYING;
     parole_gst_change_state (gst, GST_STATE_PLAYING);
 }
 
@@ -406,3 +742,44 @@ void parole_gst_terminate (ParoleGst *gst)
     gst->priv->target = GST_STATE_NULL;
     parole_gst_change_state (gst, GST_STATE_NULL);
 }
+
+GtkWidget *parole_gst_get_controls (ParoleGst *gst)
+{
+    g_return_val_if_fail (gst->priv->playbin != NULL, NULL);
+    
+    return gst->priv->controls;
+}
+
+static gboolean parole_gst_dbus_quit (ParoleGst *gst,
+				      GError **error);
+
+#include "org.parole.media.plugin.h"
+
+/*
+ * DBus server implementation
+ */
+static void 
+parole_gst_dbus_class_init (ParoleGstClass *klass)
+{
+    
+    dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (klass),
+                                     &dbus_glib_parole_gst_object_info);
+                                     
+}
+
+static void
+parole_gst_dbus_init (ParoleGst *gst)
+{
+    dbus_g_connection_register_g_object (parole_g_session_bus_get (),
+                                         "/org/Parole/Media/Plugin",
+                                         G_OBJECT (gst));
+}
+
+static gboolean
+parole_gst_dbus_quit (ParoleGst *gst,
+		      GError **error)
+{
+    parole_gst_terminate (gst);
+    
+    return TRUE;
+}
diff --git a/browser-plugin/media-plugin/parole-gst.h b/browser-plugin/media-plugin/parole-gst.h
index 72a08b5..c37ea2b 100644
--- a/browser-plugin/media-plugin/parole-gst.h
+++ b/browser-plugin/media-plugin/parole-gst.h
@@ -54,6 +54,8 @@ void				parole_gst_play_url	   (ParoleGst *gst,
 							    
 void				parole_gst_terminate	   (ParoleGst *gst);
 
+GtkWidget		       *parole_gst_get_controls    (ParoleGst *gst);
+
 G_END_DECLS
 
 #endif /* __PAROLE_GST_H */
diff --git a/browser-plugin/parole-plugin.cpp b/browser-plugin/parole-plugin.cpp
index d68f3f7..d6a986c 100644
--- a/browser-plugin/parole-plugin.cpp
+++ b/browser-plugin/parole-plugin.cpp
@@ -109,9 +109,30 @@ NPError ParolePlugin::NewStream (NPMIMEType type, NPStream *stream,
 
 ParolePlugin::ParolePlugin (NPP pNPInstance)
 {
+    GError *error = NULL;
+    
     g_debug ("Constructor");
     window_set = FALSE;
     url = NULL;
+    bus = NULL;
+    proxy = NULL;
+    
+    bus = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
+    
+    if ( error )
+    {
+	g_critical ("%s : ", error->message);
+	g_error_free (error);
+	return;
+    }
+   
+    proxy = dbus_g_proxy_new_for_name (bus, 
+				       "org.Parole.Media.Plugin",
+				       "/org/Parole/Media/Plugin",
+				       "org.Parole.Media.Plugin");
+    
+    if ( !proxy ) 
+	g_critical ("Unable to create proxy for 'org.Parole.Media.Plugin'");
 }
 
 ParolePlugin::~ParolePlugin ()
@@ -119,6 +140,13 @@ ParolePlugin::~ParolePlugin ()
     if ( url )
 	g_free (url);
     g_debug ("Destructor");
+    
+    if ( proxy )
+    {
+	dbus_g_proxy_call_no_reply (proxy, "Quit",
+				    G_TYPE_INVALID,
+				    G_TYPE_INVALID);
+    }
 }
 
 char *ParolePlugin::PluginName (void)
diff --git a/browser-plugin/parole-plugin.h b/browser-plugin/parole-plugin.h
index 82664de..d1d4a7f 100644
--- a/browser-plugin/parole-plugin.h
+++ b/browser-plugin/parole-plugin.h
@@ -32,6 +32,7 @@
 #include <npupp.h>
 
 #include <gtk/gtk.h>
+#include <dbus/dbus-glib.h>
 
 class ParolePlugin
 {
@@ -59,9 +60,12 @@ public:
     static char       *PluginDescription(void);
 
 private:
-    gboolean 	window_set;
-    gchar      *url;
-    Window      window;
+    DBusGConnection *bus;
+    DBusGProxy      *proxy;
+    
+    gboolean 	     window_set;
+    gchar           *url;
+    Window           window;
 };
 
 #endif // __PAROLE_PLUGIN_H__
diff --git a/common/Makefile.am b/common/Makefile.am
new file mode 100644
index 0000000..d04e3b1
--- /dev/null
+++ b/common/Makefile.am
@@ -0,0 +1,9 @@
+noinst_LTLIBRARIES = 			\
+	libparoledbus.la
+
+libparoledbus_la_SOURCES =		\
+	parole-dbus.c			\
+	parole-dbus.h
+	
+libparoledbus_la_CFLAGS =		\
+	$(DBUS_GLIB_CFLAGS)
diff --git a/parole/parole-dbus.c b/common/parole-dbus.c
similarity index 100%
rename from parole/parole-dbus.c
rename to common/parole-dbus.c
diff --git a/parole/parole-dbus.h b/common/parole-dbus.h
similarity index 100%
rename from parole/parole-dbus.h
rename to common/parole-dbus.h
diff --git a/configure.ac.in b/configure.ac.in
index 032188a..08ad2bb 100644
--- a/configure.ac.in
+++ b/configure.ac.in
@@ -236,6 +236,7 @@ data/icons/scalable/apps/Makefile
 data/icons/scalable/status/Makefile
 data/mime/Makefile
 data/desktop/Makefile
+common/Makefile
 parole/Makefile
 plugins/Makefile
 plugins/properties/Makefile
diff --git a/data/interfaces/browser-plugin-control.ui b/data/interfaces/browser-plugin-control.ui
index 8fc2c38..3aa9a9b 100644
--- a/data/interfaces/browser-plugin-control.ui
+++ b/data/interfaces/browser-plugin-control.ui
@@ -1,4 +1,41 @@
 <?xml version="1.0"?>
 <interface>
+  <requires lib="gtk+" version="2.16"/>
   <!-- interface-naming-policy project-wide -->
+  <object class="GtkHBox" id="controls">
+    <property name="visible">True</property>
+    <property name="spacing">2</property>
+    <child>
+      <object class="GtkButton" id="play">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="receives_default">False</property>
+        <property name="image">image1</property>
+        <property name="relief">none</property>
+      </object>
+      <packing>
+        <property name="expand">False</property>
+        <property name="fill">False</property>
+        <property name="position">0</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkHScale" id="scale">
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <property name="draw_value">False</property>
+      </object>
+      <packing>
+        <property name="position">1</property>
+      </packing>
+    </child>
+    <child>
+      <placeholder/>
+    </child>
+  </object>
+  <object class="GtkImage" id="image1">
+    <property name="visible">True</property>
+    <property name="stock">gtk-media-play</property>
+    <property name="icon-size">1</property>
+  </object>
 </interface>
diff --git a/parole/Makefile.am b/parole/Makefile.am
index 995396d..fd135cd 100644
--- a/parole/Makefile.am
+++ b/parole/Makefile.am
@@ -7,6 +7,7 @@ INCLUDES =					\
 	-I$(top_srcdir)				\
 	-I$(top_srcdir)/data			\
 	-I$(top_srcdir)/data/mime		\
+	-I$(top_srcdir)/common                  \
 	-DLOCALEDIR=\"$(localedir)\"		\
 	-DG_LOG_DOMAIN=\"parole\"		\
 	-DPAROLE_PLUGINS_DIR=\"$(libdir)/parole-$(PAROLE_VERSION_API)\"\
@@ -24,6 +25,7 @@ PAROLE_LDFLAGS =				\
 	-export-symbols-regex "^[[^_]].*"
 
 PAROLE_LIBS = 					\
+	$(top_builddir)/common/libparoledbus.la \
         $(GTHREAD_LIBS)                         \
 	$(GIO_LIBS)				\
         $(DBUS_GLIB_LIBS)                       \
@@ -59,7 +61,6 @@ NOINST_HFILES =					\
 	parole-rc-utils.h			\
 	parole-utils.h				\
 	parole-disc.h				\
-	parole-dbus.h				\
 	parole-medialist.h			\
 	parole-debug.h				\
 	parole-plugins-manager.h		\
@@ -101,7 +102,6 @@ libparole_la_SOURCES =				\
 	parole-disc.c				\
 	parole-rc-utils.c			\
 	parole-utils.c				\
-	parole-dbus.c				\
 	parole-debug.c				\
 	parole-plugins-manager.c		\
 	parole-plugin.c				\
diff --git a/parole/parole-gst.c b/parole/parole-gst.c
index 4c92123..d255b05 100644
--- a/parole/parole-gst.c
+++ b/parole/parole-gst.c
@@ -122,7 +122,9 @@ parole_gst_finalize (GObject *object)
     
     if ( gst->priv->tick_id != 0)
 	g_source_remove (gst->priv->tick_id);
-	
+    
+    g_object_unref (gst->priv->playbin);
+    
     parole_stream_init_properties (gst->priv->stream);
     
     g_object_unref (gst->priv->stream);



More information about the Xfce4-commits mailing list