diff pidgin/gtkmedia.c @ 25686:3bf9748fdef0

Preliminary video embedded in the conversation window. It's still kind of buggy.
author Mike Ruprecht <maiku@soc.pidgin.im>
date Tue, 10 Jun 2008 05:18:29 +0000
parents 54adcf17d271
children ddbea813862e
line wrap: on
line diff
--- a/pidgin/gtkmedia.c	Sun Jun 08 02:47:38 2008 +0000
+++ b/pidgin/gtkmedia.c	Tue Jun 10 05:18:29 2008 +0000
@@ -28,11 +28,14 @@
 #include "internal.h"
 #include "connection.h"
 #include "media.h"
+#include "pidgin.h"
 
 #include "gtkmedia.h"
 
 #ifdef USE_VV
 
+#include <gst/interfaces/xoverlay.h>
+
 typedef enum
 {
 	/* Waiting for response */
@@ -60,6 +63,10 @@
 	GtkWidget *recv_progress;
 
 	PidginMediaState state;
+
+	GtkWidget *display;
+	GtkWidget *local_video;
+	GtkWidget *remote_video;
 };
 
 #define PIDGIN_MEDIA_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), PIDGIN_TYPE_MEDIA, PidginMediaPrivate))
@@ -178,6 +185,8 @@
 
 	gtk_widget_show_all(media->priv->accept);
 	gtk_widget_show_all(media->priv->reject);
+
+	media->priv->display = gtk_vbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
 }
 
 static gboolean
@@ -246,6 +255,8 @@
 		gst_object_unref(gtkmedia->priv->send_level);
 	if (gtkmedia->priv->recv_level)
 		gst_object_unref(gtkmedia->priv->recv_level);
+	if (gtkmedia->priv->display)
+		gtk_widget_destroy(gtkmedia->priv->display);
 }
 
 static void
@@ -254,6 +265,12 @@
 	g_signal_emit(gtkmedia, pidgin_media_signals[MESSAGE], 0, msg);
 }
 
+GtkWidget *
+pidgin_media_get_display_widget(GtkWidget *gtkmedia)
+{
+	return PIDGIN_MEDIA_GET_PRIVATE(gtkmedia)->display;
+}
+
 static gboolean
 media_bus_call(GstBus *bus, GstMessage *msg, gpointer gtkmedia)
 {
@@ -284,30 +301,57 @@
 	return TRUE;
 }
 
+static gboolean
+create_window (GstBus *bus, GstMessage *message, PidginMedia *gtkmedia)
+{
+	char *name;
+
+	if (GST_MESSAGE_TYPE(message) != GST_MESSAGE_ELEMENT)
+		return TRUE;
+
+	if (!gst_structure_has_name(message->structure, "prepare-xwindow-id"))
+		return TRUE;
+
+	name = gst_object_get_name(GST_MESSAGE_SRC (message));
+	purple_debug_info("gtkmedia", "prepare-xwindow-id object name: %s\n", name);
+
+	/* The XOverlay's name is the sink's name with a suffix */
+	if (!strncmp(name, "purplevideosink", strlen("purplevideosink")))
+		gst_x_overlay_set_xwindow_id(GST_X_OVERLAY(GST_MESSAGE_SRC(message)),
+					     GDK_WINDOW_XWINDOW(gtkmedia->priv->remote_video->window));
+	else if (!strncmp(name, "purplelocalvideosink", strlen("purplelocalvideosink")))
+		gst_x_overlay_set_xwindow_id(GST_X_OVERLAY(GST_MESSAGE_SRC(message)),
+					     GDK_WINDOW_XWINDOW(gtkmedia->priv->local_video->window));
+	g_free(name);
+	return TRUE;
+}
+
 static void
 pidgin_media_ready_cb(PurpleMedia *media, PidginMedia *gtkmedia)
 {
 	GstElement *element = purple_media_get_pipeline(media);
 
-	GstElement *audiosendbin, *audiosendlevel;
-	GstElement *audiorecvbin, *audiorecvlevel;
-	GstElement *videosendbin;
-	GstElement *videorecvbin;
+	GstElement *audiosendbin = NULL, *audiosendlevel = NULL;
+	GstElement *audiorecvbin = NULL, *audiorecvlevel = NULL;
+	GstElement *videosendbin = NULL;
+	GstElement *videorecvbin = NULL;
 
 	GList *sessions = purple_media_get_session_names(media);
 	GstBus *bus;
 
-	purple_media_audio_init_src(&audiosendbin, &audiosendlevel);
-	purple_media_audio_init_recv(&audiorecvbin, &audiorecvlevel);
-
-	purple_media_video_init_src(&videosendbin);
-	purple_media_video_init_recv(&videorecvbin);
-
 	for (; sessions; sessions = sessions->next) {
 		if (purple_media_get_session_type(media, sessions->data) & PURPLE_MEDIA_AUDIO) {
+			if (!audiosendbin)
+				purple_media_audio_init_src(&audiosendbin, &audiosendlevel);
+			if (!audiorecvbin)
+				purple_media_audio_init_recv(&audiorecvbin, &audiorecvlevel);
 			purple_media_set_src(media, sessions->data, audiosendbin);
 			purple_media_set_sink(media, sessions->data, audiorecvbin);
 		} else if (purple_media_get_session_type(media, sessions->data) & PURPLE_MEDIA_VIDEO) {
+			if (!videosendbin)
+				purple_media_video_init_src(&videosendbin);
+			if (!videorecvbin)
+				purple_media_video_init_recv(&videorecvbin);
 			purple_media_set_src(media, sessions->data, videosendbin);
 			purple_media_set_sink(media, sessions->data, videorecvbin);
 		}
@@ -320,9 +364,42 @@
 				       NULL);
 	}
 
+	if (videorecvbin || videosendbin) {
+		GtkWidget *aspect;
+		GtkWidget *remote_video;
+		GtkWidget *local_video;
+
+		gtk_widget_show(gtkmedia->priv->display);
+
+		aspect = gtk_aspect_frame_new(NULL, 0.5, 0.5, 4.0/3.0, FALSE);
+		gtk_frame_set_shadow_type(GTK_FRAME(aspect), GTK_SHADOW_IN);
+		gtk_box_pack_start(GTK_BOX(gtkmedia->priv->display), aspect, TRUE, TRUE, 0);
+
+		remote_video = gtk_drawing_area_new();
+		gtk_container_add(GTK_CONTAINER(aspect), remote_video);
+		gtk_widget_set_size_request (GTK_WIDGET(remote_video), 100, -1);
+		gtk_widget_show(remote_video);
+		gtk_widget_show(aspect);
+
+		aspect = gtk_aspect_frame_new(NULL, 0.5, 0.5, 4.0/3.0, FALSE);
+		gtk_frame_set_shadow_type(GTK_FRAME(aspect), GTK_SHADOW_IN);
+		gtk_box_pack_start(GTK_BOX(gtkmedia->priv->display), aspect, TRUE, TRUE, 0);
+
+		local_video = gtk_drawing_area_new();
+		gtk_container_add(GTK_CONTAINER(aspect), local_video);
+		gtk_widget_show(local_video);
+		gtk_widget_show(aspect);
+
+		gtkmedia->priv->local_video = local_video;
+		gtkmedia->priv->remote_video = remote_video;
+	}
+
 	bus = gst_pipeline_get_bus(GST_PIPELINE(element));
 	gst_bus_add_signal_watch(GST_BUS(bus));
-	g_signal_connect(G_OBJECT(gst_pipeline_get_bus(GST_PIPELINE(element))), "message", G_CALLBACK(level_message_cb), gtkmedia);
+	g_signal_connect(G_OBJECT(gst_pipeline_get_bus(GST_PIPELINE(element))),
+			 "message", G_CALLBACK(level_message_cb), gtkmedia);
+	if (videorecvbin || videosendbin)
+		gst_bus_set_sync_handler(bus, (GstBusSyncHandler)create_window, gtkmedia);
 	gst_bus_add_watch(bus, media_bus_call, gtkmedia);
 	gst_object_unref(bus);
 }