# HG changeset patch # User Mike Ruprecht # Date 1237772605 0 # Node ID d7393eebf1f41580dbb7e951c13a384696223d98 # Parent 1c73d2ef9ddce843dbe59e89748bf6ce9e3fed0e# Parent c0499eb4dd4dcf84ac414cf4ae120c74c77b04b3 merge of '85389d6ca8dc05827fa7e57e17906b2f73e2c676' and 'd1fcdfed72472e989b6233008b7293bba744532c' diff -r c0499eb4dd4d -r d7393eebf1f4 COPYRIGHT --- a/COPYRIGHT Mon Mar 23 01:43:21 2009 +0000 +++ b/COPYRIGHT Mon Mar 23 01:43:25 2009 +0000 @@ -8,6 +8,7 @@ Dave Ahlswede Manuel Amador Matt Amato +Josef Andrysek Geoffrey Antos Daniel Atallah Paul Aurich diff -r c0499eb4dd4d -r d7393eebf1f4 ChangeLog --- a/ChangeLog Mon Mar 23 01:43:21 2009 +0000 +++ b/ChangeLog Mon Mar 23 01:43:25 2009 +0000 @@ -6,8 +6,9 @@ project. With some minor additions and clean ups from Paul Aurich. XMPP: - * Add support for in-band bytestreams (XEP-0047). - * Add support for attention (XEP-0224). + * Add support for in-band bytestreams for file transfers (XEP-0047). + * Add support for sending attentions (equivalent to "buzz" and "nudge") + using the command /buzz (XEP-0224). Pidgin: * Added -f command line option to tell Pidgin to ignore NetworkManager @@ -18,6 +19,9 @@ * Pressing the Enter key in the message entry box of the New Status dialog and various other dialogs now causes the cursor to move to the next line. + * Created a unified Buddy Pounce notification window for all pounces + where "Pop up a notification" is selected, which avoids having a + new dialog box every time a pounce is triggered. (Jorge VillaseƱor) version 2.5.5 (03/01/2009): libpurple: diff -r c0499eb4dd4d -r d7393eebf1f4 ChangeLog.API --- a/ChangeLog.API Mon Mar 23 01:43:21 2009 +0000 +++ b/ChangeLog.API Mon Mar 23 01:43:25 2009 +0000 @@ -68,6 +68,7 @@ * pidgin_blist_get_theme * pidgin_sound_is_customized * pidgin_utils_init, pidgin_utils_uninit + * pidgin_notify_pounce_add perl: Changed: diff -r c0499eb4dd4d -r d7393eebf1f4 finch/gntaccount.c --- a/finch/gntaccount.c Mon Mar 23 01:43:21 2009 +0000 +++ b/finch/gntaccount.c Mon Mar 23 01:43:25 2009 +0000 @@ -1099,4 +1099,3 @@ return &ui_ops; } - diff -r c0499eb4dd4d -r d7393eebf1f4 finch/gntdebug.c --- a/finch/gntdebug.c Mon Mar 23 01:43:21 2009 +0000 +++ b/finch/gntdebug.c Mon Mar 23 01:43:25 2009 +0000 @@ -23,8 +23,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ -#include "util.h" - #include #include #include @@ -38,6 +36,7 @@ #include "gntdebug.h" #include "finch.h" #include "notify.h" +#include "util.h" #include #include diff -r c0499eb4dd4d -r d7393eebf1f4 finch/gntft.c --- a/finch/gntft.c Mon Mar 23 01:43:21 2009 +0000 +++ b/finch/gntft.c Mon Mar 23 01:43:25 2009 +0000 @@ -25,12 +25,6 @@ */ #include "finch.h" -#include "debug.h" -#include "notify.h" -#include "ft.h" -#include "prpl.h" -#include "util.h" - #include #include #include @@ -38,6 +32,12 @@ #include #include +#include "debug.h" +#include "notify.h" +#include "ft.h" +#include "prpl.h" +#include "util.h" + #include "gntft.h" #include "prefs.h" diff -r c0499eb4dd4d -r d7393eebf1f4 finch/gntmedia.c --- a/finch/gntmedia.c Mon Mar 23 01:43:21 2009 +0000 +++ b/finch/gntmedia.c Mon Mar 23 01:43:25 2009 +0000 @@ -159,25 +159,9 @@ } static void -finch_media_ready_cb(PurpleMedia *media, FinchMedia *gntmedia) -{ - GstElement *sendbin, *sendlevel; - - GList *sessions = purple_media_get_session_names(media); - - purple_media_audio_init_src(&sendbin, &sendlevel); - - for (; sessions; sessions = sessions->next) { - purple_media_set_src(media, sessions->data, sendbin); - } - g_list_free(sessions); -} - -static void finch_media_accept_cb(PurpleMedia *media, FinchMedia *gntmedia) { GntWidget *parent; - GstElement *sendbin = NULL; finch_media_emit_message(gntmedia, _("Call in progress.")); @@ -200,9 +184,6 @@ parent = parent->parent; gnt_box_readjust(GNT_BOX(parent)); gnt_widget_draw(parent); - - purple_media_get_elements(media, &sendbin, NULL, NULL, NULL); - gst_element_set_state(GST_ELEMENT(sendbin), GST_STATE_PLAYING); } static void @@ -226,14 +207,13 @@ } static void -finch_media_state_changed_cb(PurpleMedia *media, - PurpleMediaStateChangedType type, +finch_media_state_changed_cb(PurpleMedia *media, PurpleMediaState state, gchar *sid, gchar *name, FinchMedia *gntmedia) { - purple_debug_info("gntmedia", "type: %d sid: %s name: %s\n", - type, sid, name); + purple_debug_info("gntmedia", "state: %d sid: %s name: %s\n", + state, sid, name); if (sid == NULL && name == NULL) { - if (type == PURPLE_MEDIA_STATE_CHANGED_END) { + if (state == PURPLE_MEDIA_STATE_END) { finch_media_emit_message(gntmedia, _("The call has been terminated.")); finch_conversation_set_info_widget( @@ -244,19 +224,23 @@ * to free the FinchMedia widget. */ g_object_unref(gntmedia); - } else if (type == PURPLE_MEDIA_STATE_CHANGED_REJECTED) { - finch_media_emit_message(gntmedia, - _("You have rejected the call.")); } - } else if (type == PURPLE_MEDIA_STATE_CHANGED_NEW - && sid != NULL && name != NULL) { - finch_media_ready_cb(media, gntmedia); - } else if (type == PURPLE_MEDIA_STATE_CHANGED_CONNECTED) { + } else if (state == PURPLE_MEDIA_STATE_CONNECTED) { finch_media_accept_cb(media, gntmedia); } } static void +finch_media_stream_info_cb(PurpleMedia *media, PurpleMediaInfoType type, + gchar *sid, gchar *name, FinchMedia *gntmedia) +{ + if (type == PURPLE_MEDIA_INFO_REJECT) { + finch_media_emit_message(gntmedia, + _("You have rejected the call.")); + } +} + +static void finch_media_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { FinchMedia *media; @@ -285,6 +269,8 @@ } g_signal_connect(G_OBJECT(media->priv->media), "state-changed", G_CALLBACK(finch_media_state_changed_cb), media); + g_signal_connect(G_OBJECT(media->priv->media), "stream-info", + G_CALLBACK(finch_media_stream_info_cb), media); break; } default: @@ -362,6 +348,75 @@ return PURPLE_CMD_STATUS_OK; } +static GstElement * +create_default_audio_src(void) +{ + GstElement *bin, *src, *volume; + GstPad *pad, *ghost; + const gchar *audio_device = purple_prefs_get_string( + "/purple/media/audio/device"); + double input_volume = purple_prefs_get_int( + "/purple/media/audio/volume/input")/10.0; + + bin = gst_bin_new("purplesendaudiobin"); + src = gst_element_factory_make("alsasrc", "asrc"); + volume = gst_element_factory_make("volume", "purpleaudioinputvolume"); + g_object_set(volume, "volume", input_volume, NULL); + gst_bin_add_many(GST_BIN(bin), src, volume, NULL); + gst_element_link(src, volume); + pad = gst_element_get_pad(volume, "src"); + ghost = gst_ghost_pad_new("ghostsrc", pad); + gst_element_add_pad(bin, ghost); + + if (audio_device != NULL && strcmp(audio_device, "")) + g_object_set(G_OBJECT(src), "device", audio_device, NULL); + + return bin; +} + +static GstElement * +create_default_audio_sink(void) +{ + GstElement *bin, *sink, *volume, *queue; + GstPad *pad, *ghost; + double output_volume = purple_prefs_get_int( + "/purple/media/audio/volume/output")/10.0; + + bin = gst_bin_new("pidginrecvaudiobin"); + sink = gst_element_factory_make("alsasink", "asink"); + g_object_set(G_OBJECT(sink), "async", FALSE, "sync", FALSE, NULL); + volume = gst_element_factory_make("volume", "purpleaudiooutputvolume"); + g_object_set(volume, "volume", output_volume, NULL); + queue = gst_element_factory_make("queue", NULL); + gst_bin_add_many(GST_BIN(bin), sink, volume, queue, NULL); + gst_element_link(volume, sink); + gst_element_link(queue, volume); + pad = gst_element_get_pad(queue, "sink"); + ghost = gst_ghost_pad_new("ghostsink", pad); + gst_element_add_pad(bin, ghost); + + return bin; +} + +static PurpleMediaElementInfo default_audio_src = +{ + "finchdefaultaudiosrc", /* id */ + PURPLE_MEDIA_ELEMENT_AUDIO /* type */ + | PURPLE_MEDIA_ELEMENT_SRC + | PURPLE_MEDIA_ELEMENT_ONE_SRC + | PURPLE_MEDIA_ELEMENT_UNIQUE, + create_default_audio_src, /* create */ +}; + +static PurpleMediaElementInfo default_audio_sink = +{ + "finchdefaultaudiosink", /* id */ + PURPLE_MEDIA_ELEMENT_AUDIO /* type */ + | PURPLE_MEDIA_ELEMENT_SINK + | PURPLE_MEDIA_ELEMENT_ONE_SINK, + create_default_audio_sink, /* create */ +}; + void finch_media_manager_init(void) { PurpleMediaManager *manager = purple_media_manager_get(); @@ -369,6 +424,10 @@ purple_cmd_register("call", "", PURPLE_CMD_P_DEFAULT, PURPLE_CMD_FLAG_IM, NULL, call_cmd_cb, _("call: Make an audio call."), NULL); + + purple_debug_info("gntmedia", "Registering media element types\n"); + purple_media_manager_set_active_element(manager, &default_audio_src); + purple_media_manager_set_active_element(manager, &default_audio_sink); } void finch_media_manager_uninit(void) diff -r c0499eb4dd4d -r d7393eebf1f4 finch/gntnotify.c --- a/finch/gntnotify.c Mon Mar 23 01:43:21 2009 +0000 +++ b/finch/gntnotify.c Mon Mar 23 01:43:25 2009 +0000 @@ -23,8 +23,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ -#include - #include #include #include @@ -35,6 +33,7 @@ #include "finch.h" +#include #include "gntnotify.h" #include "debug.h" diff -r c0499eb4dd4d -r d7393eebf1f4 finch/gntplugin.c --- a/finch/gntplugin.c Mon Mar 23 01:43:21 2009 +0000 +++ b/finch/gntplugin.c Mon Mar 23 01:43:25 2009 +0000 @@ -23,9 +23,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ -#include "notify.h" -#include "request.h" - #include #include #include @@ -37,6 +34,8 @@ #include "finch.h" #include "debug.h" +#include "notify.h" +#include "request.h" #include "gntplugin.h" #include "gntrequest.h" diff -r c0499eb4dd4d -r d7393eebf1f4 finch/gntpounce.c --- a/finch/gntpounce.c Mon Mar 23 01:43:21 2009 +0000 +++ b/finch/gntpounce.c Mon Mar 23 01:43:25 2009 +0000 @@ -24,16 +24,6 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA * */ -#include "internal.h" -#include "account.h" -#include "conversation.h" -#include "debug.h" -#include "notify.h" -#include "prpl.h" -#include "request.h" -#include "server.h" -#include "util.h" - #include #include #include @@ -47,6 +37,15 @@ #include "finch.h" +#include "account.h" +#include "conversation.h" +#include "debug.h" +#include "notify.h" +#include "prpl.h" +#include "request.h" +#include "server.h" +#include "util.h" + #include "gntpounce.h" diff -r c0499eb4dd4d -r d7393eebf1f4 finch/gntrequest.c --- a/finch/gntrequest.c Mon Mar 23 01:43:21 2009 +0000 +++ b/finch/gntrequest.c Mon Mar 23 01:43:25 2009 +0000 @@ -23,9 +23,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ - -#include "util.h" - #include #include #include diff -r c0499eb4dd4d -r d7393eebf1f4 finch/gntstatus.c --- a/finch/gntstatus.c Mon Mar 23 01:43:21 2009 +0000 +++ b/finch/gntstatus.c Mon Mar 23 01:43:25 2009 +0000 @@ -23,10 +23,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ - -#include -#include - #include #include #include @@ -39,6 +35,9 @@ #include "finch.h" +#include +#include + #include "gntstatus.h" static struct diff -r c0499eb4dd4d -r d7393eebf1f4 finch/gntui.c --- a/finch/gntui.c Mon Mar 23 01:43:21 2009 +0000 +++ b/finch/gntui.c Mon Mar 23 01:43:25 2009 +0000 @@ -19,9 +19,9 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ -#include #include "finch.h" +#include "gntui.h" #include "gntaccount.h" #include "gntblist.h" @@ -41,7 +41,7 @@ #include "gntstatus.h" #include "gntsound.h" -#include "gntui.h" +#include void gnt_ui_init() { diff -r c0499eb4dd4d -r d7393eebf1f4 finch/libgnt/wms/s.c --- a/finch/libgnt/wms/s.c Mon Mar 23 01:43:21 2009 +0000 +++ b/finch/libgnt/wms/s.c Mon Mar 23 01:43:25 2009 +0000 @@ -2,7 +2,6 @@ #include #include "internal.h" -#include "blist.h" #include "gnt.h" #include "gntbox.h" @@ -12,6 +11,7 @@ #include "gntwindow.h" #include "gntlabel.h" +#include "blist.h" #define TYPE_S (s_get_gtype()) diff -r c0499eb4dd4d -r d7393eebf1f4 libpurple/blist.h --- a/libpurple/blist.h Mon Mar 23 01:43:21 2009 +0000 +++ b/libpurple/blist.h Mon Mar 23 01:43:25 2009 +0000 @@ -595,7 +595,7 @@ * @param contact The optional contact to place the buddy in. * @param group The group to add the new buddy to. * @param node The insertion point. Pass in NULL to add the node as - * the last child in the given group. + * the first child in the given group. */ void purple_blist_add_buddy(PurpleBuddy *buddy, PurpleContact *contact, PurpleGroup *group, PurpleBlistNode *node); diff -r c0499eb4dd4d -r d7393eebf1f4 libpurple/circbuffer.c --- a/libpurple/circbuffer.c Mon Mar 23 01:43:21 2009 +0000 +++ b/libpurple/circbuffer.c Mon Mar 23 01:43:25 2009 +0000 @@ -68,7 +68,8 @@ /* If the fill pointer is wrapped to before the remove * pointer, we need to shift the data */ - if (in_offset < out_offset) { + if (in_offset < out_offset + || (in_offset == out_offset && buf->bufused > 0)) { int shift_n = MIN(buf->buflen - start_buflen, in_offset); memcpy(buf->buffer + start_buflen, buf->buffer, diff -r c0499eb4dd4d -r d7393eebf1f4 libpurple/dnssrv.c --- a/libpurple/dnssrv.c Mon Mar 23 01:43:21 2009 +0000 +++ b/libpurple/dnssrv.c Mon Mar 23 01:43:25 2009 +0000 @@ -175,9 +175,11 @@ end: size = g_list_length(ret); + /* TODO: Check return value */ write(out, &size, sizeof(int)); while (ret != NULL) { + /* TODO: Check return value */ write(out, ret->data, sizeof(PurpleSrvResponse)); g_free(ret->data); ret = g_list_remove(ret, ret->data); diff -r c0499eb4dd4d -r d7393eebf1f4 libpurple/media.c --- a/libpurple/media.c Mon Mar 23 01:43:21 2009 +0000 +++ b/libpurple/media.c Mon Mar 23 01:43:25 2009 +0000 @@ -38,7 +38,6 @@ #ifdef USE_VV -#include #include /** @copydoc _PurpleMediaSession */ @@ -56,9 +55,6 @@ PurpleMediaSessionType type; - gboolean codecs_ready; - - GstElement *sink; gulong window_id; }; @@ -67,7 +63,6 @@ PurpleMediaSession *session; gchar *participant; FsStream *stream; - GstElement *sink; GstElement *src; GstElement *tee; @@ -129,8 +124,8 @@ CANDIDATES_PREPARED, CODECS_CHANGED, NEW_CANDIDATE, - READY_NEW, STATE_CHANGED, + STREAM_INFO, LAST_SIGNAL }; static guint purple_media_signals[LAST_SIGNAL] = {0}; @@ -173,12 +168,36 @@ static GType type = 0; if (type == 0) { static const GEnumValue values[] = { - { PURPLE_MEDIA_STATE_CHANGED_NEW, "PURPLE_MEDIA_STATE_CHANGED_NEW", "new" }, - { PURPLE_MEDIA_STATE_CHANGED_CONNECTED, "PURPLE_MEDIA_STATE_CHANGED_CONNECTED", "connected" }, - { PURPLE_MEDIA_STATE_CHANGED_END, "PURPLE_MEDIA_STATE_CHANGED_END", "end" }, + { PURPLE_MEDIA_STATE_NEW, + "PURPLE_MEDIA_STATE_NEW", "new" }, + { PURPLE_MEDIA_STATE_CONNECTED, + "PURPLE_MEDIA_STATE_CONNECTED", "connected" }, + { PURPLE_MEDIA_STATE_END, + "PURPLE_MEDIA_STATE_END", "end" }, { 0, NULL, NULL } }; - type = g_enum_register_static("PurpleMediaStateChangedType", values); + type = g_enum_register_static("PurpleMediaState", values); + } + return type; +} + +GType +purple_media_info_type_get_type() +{ + static GType type = 0; + if (type == 0) { + static const GEnumValue values[] = { + { PURPLE_MEDIA_INFO_HANGUP, + "PURPLE_MEDIA_INFO_HANGUP", "hangup" }, + { PURPLE_MEDIA_INFO_REJECT, + "PURPLE_MEDIA_INFO_REJECT", "reject" }, + { PURPLE_MEDIA_INFO_MUTE, + "PURPLE_MEDIA_INFO_MUTE", "mute" }, + { PURPLE_MEDIA_INFO_HOLD, + "PURPLE_MEDIA_INFO_HOLD", "hold" }, + { 0, NULL, NULL } + }; + type = g_enum_register_static("PurpleMediaInfoType", values); } return type; } @@ -249,14 +268,15 @@ purple_smarshal_VOID__POINTER_POINTER_OBJECT, G_TYPE_NONE, 3, G_TYPE_POINTER, G_TYPE_POINTER, PURPLE_TYPE_MEDIA_CANDIDATE); - purple_media_signals[READY_NEW] = g_signal_new("ready-new", G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_LAST, 0, NULL, NULL, - purple_smarshal_VOID__STRING_STRING, - G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_STRING); purple_media_signals[STATE_CHANGED] = g_signal_new("state-changed", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, purple_smarshal_VOID__ENUM_STRING_STRING, - G_TYPE_NONE, 3, PURPLE_MEDIA_TYPE_STATE_CHANGED, + G_TYPE_NONE, 3, PURPLE_MEDIA_TYPE_STATE, + G_TYPE_STRING, G_TYPE_STRING); + purple_media_signals[STREAM_INFO] = g_signal_new("stream-info", G_TYPE_FROM_CLASS(klass), + G_SIGNAL_RUN_LAST, 0, NULL, NULL, + purple_smarshal_VOID__ENUM_STRING_STRING, + G_TYPE_NONE, 3, PURPLE_MEDIA_TYPE_INFO_TYPE, G_TYPE_STRING, G_TYPE_STRING); g_type_class_add_private(klass, sizeof(PurpleMediaPrivate)); } @@ -921,26 +941,6 @@ return type; } - - -PurpleMediaSessionType -purple_media_get_overall_type(PurpleMedia *media) -{ - GList *values; - PurpleMediaSessionType type = PURPLE_MEDIA_NONE; - - g_return_val_if_fail(PURPLE_IS_MEDIA(media), type); - - values = g_hash_table_get_values(media->priv->sessions); - - for (; values; values = g_list_delete_link(values, values)) { - PurpleMediaSession *session = values->data; - type |= session->type; - } - - return type; -} - static PurpleMediaSession* purple_media_get_session(PurpleMedia *media, const gchar *sess_id) { @@ -1091,37 +1091,7 @@ g_hash_table_get_keys(media->priv->sessions) : NULL; } -void -purple_media_get_elements(PurpleMedia *media, GstElement **audio_src, GstElement **audio_sink, - GstElement **video_src, GstElement **video_sink) -{ - GList *values; - - g_return_if_fail(PURPLE_IS_MEDIA(media)); - - values = g_hash_table_get_values(media->priv->sessions); - - for (; values; values = g_list_delete_link(values, values)) { - PurpleMediaSession *session = (PurpleMediaSession*)values->data; - - if (session->type & PURPLE_MEDIA_SEND_AUDIO && audio_src) - *audio_src = session->src; - if (session->type & PURPLE_MEDIA_SEND_VIDEO && video_src) - *video_src = session->src; - } - - values = media->priv->streams; - for (; values; values = g_list_next(values)) { - PurpleMediaStream *stream = (PurpleMediaStream*)values->data; - - if (stream->session->type & PURPLE_MEDIA_RECV_AUDIO && audio_sink) - *audio_sink = stream->sink; - if (stream->session->type & PURPLE_MEDIA_RECV_VIDEO && video_sink) - *video_sink = stream->sink; - } -} - -void +static void purple_media_set_src(PurpleMedia *media, const gchar *sess_id, GstElement *src) { PurpleMediaSession *session; @@ -1158,7 +1128,8 @@ gst_element_set_locked_state(session->src, FALSE); } -void +#if 0 +static void purple_media_set_sink(PurpleMedia *media, const gchar *sess_id, const gchar *participant, GstElement *sink) { @@ -1180,6 +1151,7 @@ gst_bin_add(GST_BIN(stream->session->media->priv->confbin), stream->sink); } +#endif GstElement * purple_media_get_src(PurpleMedia *media, const gchar *sess_id) @@ -1190,15 +1162,6 @@ return (session != NULL) ? session->src : NULL; } -GstElement * -purple_media_get_sink(PurpleMedia *media, const gchar *sess_id, const gchar *participant) -{ - PurpleMediaStream *stream; - g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL); - stream = purple_media_get_stream(media, sess_id, participant); - return (stream != NULL) ? stream->sink : NULL; -} - static PurpleMediaSession * purple_media_session_from_fs_stream(PurpleMedia *media, FsStream *stream) { @@ -1226,57 +1189,6 @@ return NULL; } -/* This could also emit when participants are ready */ -static void -purple_media_emit_ready(PurpleMedia *media, PurpleMediaSession *session, const gchar *participant) -{ - GList *sessions; - gboolean conf_ready = TRUE; - - g_return_if_fail(PURPLE_IS_MEDIA(media)); - - if ((session != NULL) && ((media->priv->initiator == FALSE && - purple_media_accepted(media, session->id, NULL) == FALSE) || - (purple_media_codecs_ready(media, session->id) == FALSE))) - return; - - sessions = g_hash_table_get_values(media->priv->sessions); - - for (; sessions; sessions = g_list_delete_link(sessions, sessions)) { - PurpleMediaSession *session_data = sessions->data; - GList *streams = purple_media_get_streams(media, - session_data->id, NULL); - gboolean session_ready = TRUE; - - if ((media->priv->initiator == FALSE && - purple_media_accepted(media, - session->id, NULL) == FALSE) || - (purple_media_codecs_ready( - media, session_data->id) == FALSE)) - conf_ready = FALSE; - - for (; streams; streams = g_list_delete_link(streams, streams)) { - PurpleMediaStream *stream = streams->data; - if (stream->candidates_prepared == FALSE) { - session_ready = FALSE; - conf_ready = FALSE; - } else if (session_data == session) - g_signal_emit(media, purple_media_signals[READY_NEW], - 0, session_data->id, stream->participant); - } - - if (session_ready == TRUE && - (session == session_data || session == NULL)) - g_signal_emit(media, purple_media_signals[READY_NEW], - 0, session_data->id, NULL); - } - - if (conf_ready == TRUE) { - g_signal_emit(media, purple_media_signals[READY_NEW], - 0, NULL, NULL); - } -} - static gboolean media_bus_call(GstBus *bus, GstMessage *msg, PurpleMedia *media) { @@ -1365,16 +1277,7 @@ for (; sessions; sessions = g_list_delete_link(sessions, sessions)) { PurpleMediaSession *session = sessions->data; if (session->session == fssession) { - gboolean ready; - gchar *session_id; - - g_object_get(session->session, "codecs-ready", &ready, NULL); - if (session->codecs_ready == FALSE && ready == TRUE) { - session->codecs_ready = ready; - purple_media_emit_ready(media, session, NULL); - } - - session_id = g_strdup(session->id); + gchar *session_id = g_strdup(session->id); g_signal_emit(media, purple_media_signals[CODECS_CHANGED], 0, session_id); g_free(session_id); g_list_free(sessions); @@ -1445,7 +1348,6 @@ void purple_media_accept(PurpleMedia *media) { - GList *sessions; GList *streams; g_return_if_fail(PURPLE_IS_MEDIA(media)); @@ -1462,24 +1364,14 @@ g_signal_emit(media, purple_media_signals[ACCEPTED], 0, NULL, NULL); - - sessions = g_hash_table_get_values(media->priv->sessions); - - for (; sessions; sessions = g_list_delete_link(sessions, sessions)) { - PurpleMediaSession *session = sessions->data; - - if (media->priv->initiator == FALSE) - purple_media_emit_ready(media, session, NULL); - } - } void purple_media_hangup(PurpleMedia *media) { g_return_if_fail(PURPLE_IS_MEDIA(media)); - g_signal_emit(media, purple_media_signals[STATE_CHANGED], - 0, PURPLE_MEDIA_STATE_CHANGED_HANGUP, + g_signal_emit(media, purple_media_signals[STREAM_INFO], + 0, PURPLE_MEDIA_INFO_HANGUP, NULL, NULL); purple_media_end(media, NULL, NULL); } @@ -1488,8 +1380,8 @@ purple_media_reject(PurpleMedia *media) { g_return_if_fail(PURPLE_IS_MEDIA(media)); - g_signal_emit(media, purple_media_signals[STATE_CHANGED], - 0, PURPLE_MEDIA_STATE_CHANGED_REJECTED, + g_signal_emit(media, purple_media_signals[STREAM_INFO], + 0, PURPLE_MEDIA_INFO_REJECT, NULL, NULL); purple_media_end(media, NULL, NULL); } @@ -1501,197 +1393,12 @@ g_return_if_fail(PURPLE_IS_MEDIA(media)); if (session_id == NULL && participant == NULL) { g_signal_emit(media, purple_media_signals[STATE_CHANGED], - 0, PURPLE_MEDIA_STATE_CHANGED_END, + 0, PURPLE_MEDIA_STATE_END, NULL, NULL); g_object_unref(media); } } -GList* -purple_media_get_devices(const gchar *plugin) -{ - GObjectClass *klass; - GstPropertyProbe *probe; - const GParamSpec *pspec; - GstElement *element = gst_element_factory_make(plugin, NULL); - GstElementFactory *factory; - const gchar *longname = NULL; - GList *ret = NULL; - - if (element == NULL) - return NULL; - - factory = gst_element_get_factory(element); - - longname = gst_element_factory_get_longname(factory); - klass = G_OBJECT_GET_CLASS(element); - - if (!g_object_class_find_property (klass, "device") || - !GST_IS_PROPERTY_PROBE (element) || - !(probe = GST_PROPERTY_PROBE (element)) || - !(pspec = gst_property_probe_get_property (probe, "device"))) { - purple_debug_info("media", "Found source '%s' (%s) - no device\n", - longname, GST_PLUGIN_FEATURE (factory)->name); - } else { - gint n; - gchar *name; - GValueArray *array; - - purple_debug_info("media", "Found devices\n"); - - /* Set autoprobe[-fps] to FALSE to avoid delays when probing. */ - if (g_object_class_find_property (klass, "autoprobe")) { - g_object_set (G_OBJECT (element), "autoprobe", FALSE, NULL); - if (g_object_class_find_property (klass, "autoprobe-fps")) { - g_object_set (G_OBJECT (element), "autoprobe-fps", FALSE, NULL); - } - } - - array = gst_property_probe_probe_and_get_values (probe, pspec); - if (array != NULL) { - for (n = 0 ; n < array->n_values ; n++) { - GValue *device = g_value_array_get_nth (array, n); - - ret = g_list_append(ret, g_value_dup_string(device)); - - g_object_set(G_OBJECT(element), "device", - g_value_get_string(device), NULL); - g_object_get(G_OBJECT(element), "device-name", &name, NULL); - purple_debug_info("media", "Found source '%s' (%s) - device '%s' (%s)\n", - longname, GST_PLUGIN_FEATURE (factory)->name, - name, g_value_get_string(device)); - g_free(name); - } - g_value_array_free(array); - } - - /* Restore autoprobe[-fps] to TRUE. */ - if (g_object_class_find_property (klass, "autoprobe")) { - g_object_set (G_OBJECT (element), "autoprobe", TRUE, NULL); - if (g_object_class_find_property (klass, "autoprobe-fps")) { - g_object_set (G_OBJECT (element), "autoprobe-fps", TRUE, NULL); - } - } - } - - gst_object_unref(element); - return ret; -} - -gchar * -purple_media_element_get_device(GstElement *element) -{ - gchar *device; - g_object_get(G_OBJECT(element), "device", &device, NULL); - return device; -} - -void -purple_media_audio_init_src(GstElement **sendbin, GstElement **sendlevel) -{ - GstElement *src; - GstElement *volume; - GstPad *pad; - GstPad *ghost; - const gchar *audio_device = purple_prefs_get_string("/purple/media/audio/device"); - double input_volume = purple_prefs_get_int("/purple/media/audio/volume/input")/10.0; - - g_return_if_fail(sendbin != NULL && sendlevel != NULL); - - *sendbin = gst_bin_new("purplesendaudiobin"); - src = gst_element_factory_make("alsasrc", "asrc"); - volume = gst_element_factory_make("volume", "purpleaudioinputvolume"); - g_object_set(volume, "volume", input_volume, NULL); - *sendlevel = gst_element_factory_make("level", "sendlevel"); - gst_bin_add_many(GST_BIN(*sendbin), src, volume, *sendlevel, NULL); - gst_element_link(src, volume); - gst_element_link(volume, *sendlevel); - pad = gst_element_get_pad(*sendlevel, "src"); - ghost = gst_ghost_pad_new("ghostsrc", pad); - gst_element_add_pad(*sendbin, ghost); - g_object_set(G_OBJECT(*sendlevel), "message", TRUE, NULL); - - if (audio_device != NULL && strcmp(audio_device, "")) - g_object_set(G_OBJECT(src), "device", audio_device, NULL); -} - -void -purple_media_video_init_src(GstElement **sendbin) -{ - GstElement *src, *videoscale, *capsfilter; - GstPad *pad; - GstPad *ghost; - GstCaps *caps; - const gchar *video_plugin = purple_prefs_get_string( - "/purple/media/video/plugin"); - const gchar *video_device = purple_prefs_get_string( - "/purple/media/video/device"); - - g_return_if_fail(sendbin != NULL); - - *sendbin = gst_bin_new("purplesendvideobin"); - src = gst_element_factory_make(video_plugin, "purplevideosource"); - videoscale = gst_element_factory_make("videoscale", NULL); - capsfilter = gst_element_factory_make("capsfilter", NULL); - - /* It was recommended to set the size < 352x288 and framerate < 20 */ - caps = gst_caps_from_string("video/x-raw-yuv , width=[250,350] , " - "height=[200,275] , framerate=[10/1,20/1]"); - g_object_set(G_OBJECT(capsfilter), "caps", caps, NULL); - - gst_bin_add_many(GST_BIN(*sendbin), src, videoscale, capsfilter, NULL); - gst_element_link_many(src, videoscale, capsfilter, NULL); - - if (!strcmp(video_plugin, "videotestsrc")) { - /* unless is-live is set to true it doesn't throttle videotestsrc */ - g_object_set (G_OBJECT(src), "is-live", TRUE, NULL); - } - - pad = gst_element_get_static_pad(capsfilter, "src"); - ghost = gst_ghost_pad_new("ghostsrc", pad); - gst_object_unref(pad); - gst_element_add_pad(*sendbin, ghost); - - if (video_device != NULL && strcmp(video_device, "")) - g_object_set(G_OBJECT(src), "device", video_device, NULL); -} - -void -purple_media_audio_init_recv(GstElement **recvbin, GstElement **recvlevel) -{ - GstElement *sink, *volume, *queue; - GstPad *pad, *ghost; - double output_volume = purple_prefs_get_int( - "/purple/media/audio/volume/output")/10.0; - - g_return_if_fail(recvbin != NULL && recvlevel != NULL); - - *recvbin = gst_bin_new("pidginrecvaudiobin"); - sink = gst_element_factory_make("alsasink", "asink"); - g_object_set(G_OBJECT(sink), "async", FALSE, "sync", FALSE, NULL); - volume = gst_element_factory_make("volume", "purpleaudiooutputvolume"); - g_object_set(volume, "volume", output_volume, NULL); - *recvlevel = gst_element_factory_make("level", "recvlevel"); - queue = gst_element_factory_make("queue", NULL); - gst_bin_add_many(GST_BIN(*recvbin), sink, volume, - *recvlevel, queue, NULL); - gst_element_link(*recvlevel, sink); - gst_element_link(volume, *recvlevel); - gst_element_link(queue, volume); - pad = gst_element_get_pad(queue, "sink"); - ghost = gst_ghost_pad_new("ghostsink", pad); - gst_element_add_pad(*recvbin, ghost); - g_object_set(G_OBJECT(*recvlevel), "message", TRUE, NULL); -} - -void -purple_media_video_init_recv(GstElement **recvbin) -{ - g_return_if_fail(recvbin != NULL); - - *recvbin = gst_element_factory_make("autovideosink", NULL); -} - static void purple_media_new_local_candidate_cb(FsStream *stream, FsCandidate *local_candidate, @@ -1740,7 +1447,6 @@ purple_media_signals[CANDIDATES_PREPARED], 0, session->id, name); - purple_media_emit_ready(session->media, session, name); g_free(name); } @@ -1819,7 +1525,7 @@ g_signal_emit(stream->session->media, purple_media_signals[STATE_CHANGED], - 0, PURPLE_MEDIA_STATE_CHANGED_CONNECTED, + 0, PURPLE_MEDIA_STATE_CONNECTED, stream->session->id, stream->participant); return FALSE; } @@ -1869,13 +1575,6 @@ gst_pad_link(srcpad, sinkpad); gst_object_unref(sinkpad); - if (codec->media_type == FS_MEDIA_TYPE_VIDEO && - stream->sink != NULL) { - gst_bin_add(GST_BIN(priv->confbin), stream->sink); - gst_element_set_state(stream->sink, GST_STATE_PLAYING); - gst_element_link(stream->tee, stream->sink); - } - stream->connected_cb_id = purple_timeout_add(0, (GSourceFunc)purple_media_connected_cb, stream); } @@ -1958,7 +1657,7 @@ purple_media_add_session(media, session); g_signal_emit(media, purple_media_signals[STATE_CHANGED], - 0, PURPLE_MEDIA_STATE_CHANGED_NEW, + 0, PURPLE_MEDIA_STATE_NEW, session->id, NULL); session_type = purple_media_from_fs(type, FS_DIRECTION_SEND); @@ -1979,7 +1678,7 @@ return FALSE; } else { g_signal_emit(media, purple_media_signals[STATE_CHANGED], - 0, PURPLE_MEDIA_STATE_CHANGED_NEW, + 0, PURPLE_MEDIA_STATE_NEW, NULL, who); } @@ -2080,7 +1779,7 @@ "src-pad-added", G_CALLBACK(purple_media_src_pad_added_cb), stream); g_signal_emit(media, purple_media_signals[STATE_CHANGED], - 0, PURPLE_MEDIA_STATE_CHANGED_NEW, + 0, PURPLE_MEDIA_STATE_NEW, session->id, who); } else if (*direction != type_direction) { /* change direction */ @@ -2418,10 +2117,27 @@ PurpleMediaStream *stream = streams->data; if (stream->session->type & PURPLE_MEDIA_RECV_AUDIO) { - GstElement *volume = gst_bin_get_by_name( - GST_BIN(stream->sink), - "purpleaudiooutputvolume"); - g_object_set(volume, "volume", level, NULL); + GstElement *tee = stream->tee; + GstIterator *iter = gst_element_iterate_src_pads(tee); + GstPad *sinkpad; + while (gst_iterator_next(iter, (gpointer)&sinkpad) + == GST_ITERATOR_OK) { + GstPad *peer = gst_pad_get_peer(sinkpad); + GstElement *volume; + + if (peer == NULL) { + gst_object_unref(sinkpad); + continue; + } + + volume = gst_bin_get_by_name(GST_BIN( + GST_OBJECT_PARENT(peer)), + "purpleaudiooutputvolume"); + g_object_set(volume, "volume", level, NULL); + gst_object_unref(peer); + gst_object_unref(sinkpad); + } + gst_iterator_free(iter); } } } diff -r c0499eb4dd4d -r d7393eebf1f4 libpurple/media.h --- a/libpurple/media.h Mon Mar 23 01:43:21 2009 +0000 +++ b/libpurple/media.h Mon Mar 23 01:43:25 2009 +0000 @@ -44,7 +44,8 @@ #define PURPLE_IS_MEDIA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), PURPLE_TYPE_MEDIA)) #define PURPLE_MEDIA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), PURPLE_TYPE_MEDIA, PurpleMediaClass)) -#define PURPLE_MEDIA_TYPE_STATE_CHANGED (purple_media_state_changed_get_type()) +#define PURPLE_MEDIA_TYPE_STATE (purple_media_state_changed_get_type()) +#define PURPLE_MEDIA_TYPE_INFO_TYPE (purple_media_info_type_get_type()) /** @copydoc _PurpleMedia */ typedef struct _PurpleMedia PurpleMedia; @@ -90,12 +91,18 @@ /** Media state-changed types */ typedef enum { - PURPLE_MEDIA_STATE_CHANGED_NEW = 0, - PURPLE_MEDIA_STATE_CHANGED_CONNECTED, - PURPLE_MEDIA_STATE_CHANGED_REJECTED, /** Local user rejected the stream. */ - PURPLE_MEDIA_STATE_CHANGED_HANGUP, /** Local user hung up the stream */ - PURPLE_MEDIA_STATE_CHANGED_END, -} PurpleMediaStateChangedType; + PURPLE_MEDIA_STATE_NEW = 0, + PURPLE_MEDIA_STATE_CONNECTED, + PURPLE_MEDIA_STATE_END, +} PurpleMediaState; + +/** Media info types */ +typedef enum { + PURPLE_MEDIA_INFO_HANGUP = 0, + PURPLE_MEDIA_INFO_REJECT, + PURPLE_MEDIA_INFO_MUTE, + PURPLE_MEDIA_INFO_HOLD, +} PurpleMediaInfoType; typedef enum { PURPLE_MEDIA_CANDIDATE_TYPE_HOST, @@ -182,6 +189,13 @@ GType purple_media_state_changed_get_type(void); /** + * Gets the type of the info type enum + * + * @return The info type enum's GType + */ +GType purple_media_info_type_get_type(void); + +/** * Gets the type of the media candidate structure. * * @return The media canditate's GType @@ -300,15 +314,6 @@ void purple_media_codec_list_free(GList *codecs); /** - * Combines all the separate session types into a single PurpleMediaSessionType. - * - * @param media The media session to retrieve session types from. - * - * @return Combined type. - */ -PurpleMediaSessionType purple_media_get_overall_type(PurpleMedia *media); - -/** * Gets a list of session names. * * @param media The media session to retrieve session names from. @@ -318,41 +323,6 @@ GList *purple_media_get_session_names(PurpleMedia *media); /** - * Gets an audio and video source and sink from the media session. - * - * Retrieves the first of each element in the media session. - * - * @param media The media session to retreive the sources and sinks from. - * @param audio_src Set to the audio source. - * @param audio_sink Set to the audio sink. - * @param video_src Set to the video source. - * @param video_sink Set to the video sink. - */ -void purple_media_get_elements(PurpleMedia *media, - GstElement **audio_src, GstElement **audio_sink, - GstElement **video_src, GstElement **video_sink); - -/** - * Sets the source on a session. - * - * @param media The media object the session is in. - * @param sess_id The session id of the session to set the source on. - * @param src The source to set the session source to. - */ -void purple_media_set_src(PurpleMedia *media, const gchar *sess_id, GstElement *src); - -/** - * Sets the sink on a stream. - * - * @param media The media object the session is in. - * @param sess_id The session id the stream belongs to. - * @param sess_id The participant the stream is associated with. - * @param sink The source to set the session sink to. - */ -void purple_media_set_sink(PurpleMedia *media, const gchar *sess_id, - const gchar *participant, GstElement *sink); - -/** * Gets the source from a session * * @param media The media object the session is in. @@ -363,17 +333,6 @@ GstElement *purple_media_get_src(PurpleMedia *media, const gchar *sess_id); /** - * Gets the sink from a stream - * - * @param media The media object the session is in. - * @param sess_id The session id the stream belongs to. - * @param participant The participant the stream is associated with. - * - * @return The sink retrieved. - */ -GstElement *purple_media_get_sink(PurpleMedia *media, const gchar *sess_id, const gchar *participant); - -/** * Gets the pipeline from the media session. * * @param media The media session to retrieve the pipeline from. @@ -449,55 +408,6 @@ const gchar *participant); /** - * Enumerates a list of devices. - * - * @param plugin The name of the GStreamer plugin from which to enumerate devices. - * - * @return The list of enumerated devices. - */ -GList *purple_media_get_devices(const gchar *plugin); - -/** - * Gets the device the plugin is currently set to. - * - * @param element The plugin to retrieve the device from. - * - * @return The device retrieved. - */ -gchar *purple_media_element_get_device(GstElement *element); - -/** - * Creates a default audio source. - * - * @param sendbin Set to the newly created audio source. - * @param sendlevel Set to the newly created level within the audio source. - */ -void purple_media_audio_init_src(GstElement **sendbin, - GstElement **sendlevel); - -/** - * Creates a default video source. - * - * @param sendbin Set to the newly created video source. - */ -void purple_media_video_init_src(GstElement **sendbin); - -/** - * Creates a default audio sink. - * - * @param recvbin Set to the newly created audio sink. - * @param recvlevel Set to the newly created level within the audio sink. - */ -void purple_media_audio_init_recv(GstElement **recvbin, GstElement **recvlevel); - -/** - * Creates a default video sink. - * - * @param sendbin Set to the newly created video sink. - */ -void purple_media_video_init_recv(GstElement **sendbin); - -/** * Adds a stream to a session. * * It only adds a stream to one audio session or video session as @@ -679,12 +589,36 @@ void purple_media_set_output_volume(PurpleMedia *media, const gchar *session_id, const gchar *participant, double level); +/** + * Sets a video output window for the given session/stream. + * + * @param media The media instance to set the output window on. + * @param session_id The session to set the output window on. + * @param participant Optionally, the participant to set the output window on. + * @param window_id The window id use for embedding the video in. + * + * @return An id to reference the output window. + */ gulong purple_media_set_output_window(PurpleMedia *media, const gchar *session_id, const gchar *participant, gulong window_id); +/** + * Removes all output windows from a given media session. + * + * @param media The instance to remove all output windows from. + */ void purple_media_remove_output_windows(PurpleMedia *media); +/** + * Gets the tee from a given session/stream. + * + * @param media The instance to get the tee from. + * @param session_id The id of the session to get the tee from. + * @param participant Optionally, the participant of the stream to get the tee from. + * + * @return The GstTee element from the chosen session/stream. + */ GstElement *purple_media_get_tee(PurpleMedia *media, const gchar *session_id, const gchar *participant); diff -r c0499eb4dd4d -r d7393eebf1f4 libpurple/protocols/jabber/google.c --- a/libpurple/protocols/jabber/google.c Mon Mar 23 01:43:21 2009 +0000 +++ b/libpurple/protocols/jabber/google.c Mon Mar 23 01:43:25 2009 +0000 @@ -210,37 +210,45 @@ google_session_send_candidates(session->media, "google-voice", session->remote_jid, session); + + g_signal_handlers_disconnect_by_func(G_OBJECT(session->media), + G_CALLBACK(google_session_ready), session); + } +} + +static void +google_session_state_changed_cb(PurpleMedia *media, PurpleMediaState state, + gchar *sid, gchar *name, GoogleSession *session) +{ + if (sid == NULL && name == NULL) { + if (state == PURPLE_MEDIA_STATE_END) { + google_session_destroy(session); + } } } static void -google_session_state_changed_cb(PurpleMedia *media, - PurpleMediaStateChangedType type, +google_session_stream_info_cb(PurpleMedia *media, PurpleMediaInfoType type, gchar *sid, gchar *name, GoogleSession *session) { - if (sid == NULL && name == NULL) { - if (type == PURPLE_MEDIA_STATE_CHANGED_END) { - google_session_destroy(session); - } else if (type == PURPLE_MEDIA_STATE_CHANGED_HANGUP) { - xmlnode *sess; - JabberIq *iq = jabber_iq_new(session->js, JABBER_IQ_SET); + if (type == PURPLE_MEDIA_INFO_HANGUP) { + xmlnode *sess; + JabberIq *iq = jabber_iq_new(session->js, JABBER_IQ_SET); + + xmlnode_set_attrib(iq->node, "to", session->remote_jid); + sess = google_session_create_xmlnode(session, "terminate"); + xmlnode_insert_child(iq->node, sess); - xmlnode_set_attrib(iq->node, "to", session->remote_jid); - sess = google_session_create_xmlnode(session, "terminate"); - xmlnode_insert_child(iq->node, sess); - - jabber_iq_send(iq); - } else if (type == PURPLE_MEDIA_STATE_CHANGED_REJECTED) { - xmlnode *sess; - JabberIq *iq = jabber_iq_new(session->js, JABBER_IQ_SET); + jabber_iq_send(iq); + } else if (type == PURPLE_MEDIA_INFO_REJECT) { + xmlnode *sess; + JabberIq *iq = jabber_iq_new(session->js, JABBER_IQ_SET); - xmlnode_set_attrib(iq->node, "to", session->remote_jid); - sess = google_session_create_xmlnode(session, "reject"); - xmlnode_insert_child(iq->node, sess); - - jabber_iq_send(iq); - } - + xmlnode_set_attrib(iq->node, "to", session->remote_jid); + sess = google_session_create_xmlnode(session, "reject"); + xmlnode_insert_child(iq->node, sess); + + jabber_iq_send(iq); } } @@ -326,6 +334,8 @@ G_CALLBACK(google_session_ready), session); g_signal_connect(G_OBJECT(session->media), "state-changed", G_CALLBACK(google_session_state_changed_cb), session); + g_signal_connect(G_OBJECT(session->media), "stream-info", + G_CALLBACK(google_session_stream_info_cb), session); g_free(params); @@ -391,6 +401,8 @@ G_CALLBACK(google_session_ready), session); g_signal_connect(G_OBJECT(session->media), "state-changed", G_CALLBACK(google_session_state_changed_cb), session); + g_signal_connect(G_OBJECT(session->media), "stream-info", + G_CALLBACK(google_session_stream_info_cb), session); purple_media_codec_list_free(codecs); @@ -498,12 +510,10 @@ google_session_handle_candidates(js, session, packet, sess); } } -#endif /* USE_VV */ void jabber_google_session_parse(JabberStream *js, xmlnode *packet) { -#ifdef USE_VV GoogleSession *session = NULL; GoogleSessionId id; @@ -560,10 +570,8 @@ session->remote_jid = g_strdup(session->id.initiator); google_session_parse_iq(js, session, packet); -#else - /* TODO: send proper error response */ +} #endif /* USE_VV */ -} static void jabber_gmail_parse(JabberStream *js, xmlnode *packet, gpointer nul) diff -r c0499eb4dd4d -r d7393eebf1f4 libpurple/protocols/jabber/google.h --- a/libpurple/protocols/jabber/google.h Mon Mar 23 01:43:21 2009 +0000 +++ b/libpurple/protocols/jabber/google.h Mon Mar 23 01:43:25 2009 +0000 @@ -27,6 +27,7 @@ #include "jabber.h" #include "media.h" +#define GOOGLE_VOICE_CAP "http://www.google.com/xmpp/protocol/voice/v1" #define GOOGLE_JINGLE_INFO_NAMESPACE "google:jingleinfo" void jabber_gmail_init(JabberStream *js); diff -r c0499eb4dd4d -r d7393eebf1f4 libpurple/protocols/jabber/iq.c --- a/libpurple/protocols/jabber/iq.c Mon Mar 23 01:43:21 2009 +0000 +++ b/libpurple/protocols/jabber/iq.c Mon Mar 23 01:43:25 2009 +0000 @@ -372,11 +372,13 @@ return; } } - + +#ifdef USE_VV if (xmlnode_get_child_with_namespace(packet, "session", "http://www.google.com/session")) { jabber_google_session_parse(js, packet); return; } +#endif if(xmlnode_get_child_with_namespace(packet, "si", "http://jabber.org/protocol/si")) { jabber_si_parse(js, packet); @@ -406,13 +408,11 @@ jabber_ibb_parse(js, packet); return; } - -#ifdef USE_VV + if (xmlnode_get_child_with_namespace(packet, "jingle", JINGLE)) { jingle_parse(js, packet); return; } -#endif /* If we get here, send the default error reply mandated by XMPP-CORE */ if(!strcmp(type, "set") || !strcmp(type, "get")) { @@ -453,9 +453,8 @@ jabber_iq_register_handler("http://jabber.org/protocol/disco#items", jabber_disco_items_parse); jabber_iq_register_handler("jabber:iq:register", jabber_register_parse); jabber_iq_register_handler("urn:xmpp:ping", urn_xmpp_ping_parse); -#ifdef USE_VV jabber_iq_register_handler(JINGLE, jingle_parse); -#endif + /* handle Google jingleinfo */ jabber_iq_register_handler(GOOGLE_JINGLE_INFO_NAMESPACE, jabber_google_handle_jingle_info); diff -r c0499eb4dd4d -r d7393eebf1f4 libpurple/protocols/jabber/jabber.c --- a/libpurple/protocols/jabber/jabber.c Mon Mar 23 01:43:21 2009 +0000 +++ b/libpurple/protocols/jabber/jabber.c Mon Mar 23 01:43:25 2009 +0000 @@ -62,13 +62,6 @@ #include "jingle/jingle.h" #include "jingle/rtp.h" -#ifdef USE_VV -#include - -#define GTALK_CAP "http://www.google.com/xmpp/protocol/voice/v1" - -#endif - #define JABBER_CONNECT_STEPS (js->gsc ? 9 : 5) static PurplePlugin *my_protocol = NULL; @@ -738,10 +731,7 @@ js->old_length = 0; js->keepalive_timeout = -1; js->certificate_CN = g_strdup(connect_server[0] ? connect_server : js->user ? js->user->domain : NULL); -#ifdef USE_VV js->sessions = NULL; -#endif - js->stun_ip = NULL; js->stun_port = 0; js->stun_query = NULL; @@ -1340,10 +1330,8 @@ { JabberStream *js = gc->proto_data; -#ifdef USE_VV /* Close all of the open Jingle sessions on this stream */ jingle_terminate_sessions(js); -#endif /* Don't perform any actions on the ssl connection * if we were forcibly disconnected because it will crash @@ -2623,12 +2611,12 @@ { return TRUE; } -#ifdef USE_VV PurpleMedia * jabber_initiate_media(PurpleConnection *gc, const char *who, PurpleMediaSessionType type) { +#ifdef USE_VV JabberStream *js = (JabberStream *) gc->proto_data; JabberBuddy *jb; @@ -2648,14 +2636,18 @@ if (type & PURPLE_MEDIA_AUDIO && !jabber_buddy_has_capability(jb, JINGLE_APP_RTP_SUPPORT_AUDIO) && - jabber_buddy_has_capability(jb, GTALK_CAP)) + jabber_buddy_has_capability(jb, GOOGLE_VOICE_CAP)) return jabber_google_session_initiate(gc->proto_data, who, type); else return jingle_rtp_initiate_media(gc->proto_data, who, type); +#else + return NULL; +#endif } PurpleMediaCaps jabber_get_media_caps(PurpleConnection *gc, const char *who) { +#ifdef USE_VV JabberStream *js = (JabberStream *) gc->proto_data; JabberBuddy *jb; PurpleMediaCaps caps = PURPLE_MEDIA_CAPS_NONE; @@ -2692,14 +2684,15 @@ caps |= PURPLE_MEDIA_CAPS_MODIFY_SESSION | PURPLE_MEDIA_CAPS_CHANGE_DIRECTION; } - if (jabber_buddy_has_capability(jb, GTALK_CAP)) + if (jabber_buddy_has_capability(jb, GOOGLE_VOICE_CAP)) caps |= PURPLE_MEDIA_CAPS_AUDIO; return caps; +#else + return PURPLE_MEDIA_CAPS_NONE; +#endif } -#endif - void jabber_register_commands(void) { purple_cmd_register("config", "", PURPLE_CMD_P_PRPL, diff -r c0499eb4dd4d -r d7393eebf1f4 libpurple/protocols/jabber/jabber.h --- a/libpurple/protocols/jabber/jabber.h Mon Mar 23 01:43:21 2009 +0000 +++ b/libpurple/protocols/jabber/jabber.h Mon Mar 23 01:43:25 2009 +0000 @@ -321,12 +321,9 @@ gboolean jabber_offline_message(const PurpleBuddy *buddy); int jabber_prpl_send_raw(PurpleConnection *gc, const char *buf, int len); GList *jabber_actions(PurplePlugin *plugin, gpointer context); +PurpleMedia *jabber_initiate_media(PurpleConnection *gc, const char *who, + PurpleMediaSessionType type); +PurpleMediaCaps jabber_get_media_caps(PurpleConnection *gc, const char *who); void jabber_register_commands(void); void jabber_init_plugin(PurplePlugin *plugin); - -#ifdef USE_VV -PurpleMedia *jabber_initiate_media(PurpleConnection *gc, const char *who, PurpleMediaSessionType type); -PurpleMediaCaps jabber_get_media_caps(PurpleConnection *gc, const char *who); -#endif - #endif /* _PURPLE_JABBER_H_ */ diff -r c0499eb4dd4d -r d7393eebf1f4 libpurple/protocols/jabber/jingle/rtp.c --- a/libpurple/protocols/jabber/jingle/rtp.c Mon Mar 23 01:43:21 2009 +0000 +++ b/libpurple/protocols/jabber/jingle/rtp.c Mon Mar 23 01:43:25 2009 +0000 @@ -335,15 +335,14 @@ } } -static void jingle_rtp_send_initiate(JingleSession *session); -static void jingle_rtp_send_accept(JingleSession *session); +static void jingle_rtp_ready(JingleSession *session); static void jingle_rtp_accepted_cb(PurpleMedia *media, gchar *sid, gchar *name, JingleSession *session) { purple_debug_info("jingle-rtp", "jingle_rtp_accepted_cb\n"); - jingle_rtp_send_accept(session); + jingle_rtp_ready(session); } static void @@ -377,8 +376,7 @@ jingle_content_set_pending_transport(content, transport); jingle_content_accept_transport(content); - jingle_rtp_send_initiate(session); - jingle_rtp_send_accept(session); + jingle_rtp_ready(session); } static void @@ -387,8 +385,7 @@ { purple_debug_info("jingle-rtp", "jingle_rtp_codecs_changed_cb: " "session_id: %s jingle_session: %p\n", sid, session); - jingle_rtp_send_initiate(session); - jingle_rtp_send_accept(session); + jingle_rtp_ready(session); } static void @@ -438,50 +435,58 @@ } static void -jingle_rtp_state_changed_cb(PurpleMedia *media, PurpleMediaStateChangedType type, +jingle_rtp_state_changed_cb(PurpleMedia *media, PurpleMediaState state, gchar *sid, gchar *name, JingleSession *session) { - purple_debug_info("jingle-rtp", "state-changed: type %d id: %s name: %s\n", type, sid, name); + purple_debug_info("jingle-rtp", "state-changed: state %d " + "id: %s name: %s\n", state, sid, name); +} - if ((type == PURPLE_MEDIA_STATE_CHANGED_REJECTED || - type == PURPLE_MEDIA_STATE_CHANGED_HANGUP) && - sid == NULL && name == NULL) { +static void +jingle_rtp_stream_info_cb(PurpleMedia *media, PurpleMediaInfoType type, + gchar *sid, gchar *name, JingleSession *session) +{ + purple_debug_info("jingle-rtp", "stream-info: type %d " + "id: %s name: %s\n", type, sid, name); + if (type == PURPLE_MEDIA_INFO_HANGUP) { jabber_iq_send(jingle_session_terminate_packet( session, "success")); g_object_unref(session); + } else if (type == PURPLE_MEDIA_INFO_REJECT) { + jabber_iq_send(jingle_session_terminate_packet( + session, "decline")); + g_object_unref(session); } } static void -jingle_rtp_send_initiate(JingleSession *session) +jingle_rtp_ready(JingleSession *session) { PurpleMedia *media = jingle_rtp_get_media(session); - if (jingle_session_is_initiator(session) == TRUE && + if (purple_media_candidates_prepared(media, NULL, NULL) && purple_media_codecs_ready(media, NULL) && - purple_media_candidates_prepared(media, NULL, NULL)) { - JabberIq *iq = jingle_session_to_packet( - session, JINGLE_SESSION_INITIATE); - jabber_iq_set_callback(iq, - jingle_rtp_initiate_ack_cb, session); - jabber_iq_send(iq); - g_signal_connect(G_OBJECT(media), "new-candidate", - G_CALLBACK(jingle_rtp_new_candidate_cb), + (jingle_session_is_initiator(session) == TRUE || + purple_media_accepted(media, NULL, NULL))) { + if (jingle_session_is_initiator(session)) { + JabberIq *iq = jingle_session_to_packet( + session, JINGLE_SESSION_INITIATE); + jabber_iq_set_callback(iq, + jingle_rtp_initiate_ack_cb, session); + jabber_iq_send(iq); + } else { + jabber_iq_send(jingle_session_to_packet(session, + JINGLE_SESSION_ACCEPT)); + } + + g_signal_handlers_disconnect_by_func(G_OBJECT(media), + G_CALLBACK(jingle_rtp_accepted_cb), session); + g_signal_handlers_disconnect_by_func(G_OBJECT(media), + G_CALLBACK(jingle_rtp_candidates_prepared_cb), session); - } -} - -static void -jingle_rtp_send_accept(JingleSession *session) -{ - PurpleMedia *media = jingle_rtp_get_media(session); - - if (jingle_session_is_initiator(session) == FALSE && - purple_media_codecs_ready(media, NULL) && - purple_media_accepted(media, NULL, NULL) && - purple_media_candidates_prepared(media, NULL, NULL)) { - jabber_iq_send(jingle_session_to_packet(session, - JINGLE_SESSION_ACCEPT)); + g_signal_handlers_disconnect_by_func(G_OBJECT(media), + G_CALLBACK(jingle_rtp_codecs_changed_cb), + session); g_signal_connect(G_OBJECT(media), "new-candidate", G_CALLBACK(jingle_rtp_new_candidate_cb), session); @@ -508,14 +513,17 @@ purple_media_set_prpl_data(media, session); /* connect callbacks */ - g_signal_connect(G_OBJECT(media), "accepted", - G_CALLBACK(jingle_rtp_accepted_cb), session); + if (jingle_session_is_initiator(session) == FALSE) + g_signal_connect(G_OBJECT(media), "accepted", + G_CALLBACK(jingle_rtp_accepted_cb), session); g_signal_connect(G_OBJECT(media), "candidates-prepared", G_CALLBACK(jingle_rtp_candidates_prepared_cb), session); g_signal_connect(G_OBJECT(media), "codecs-changed", G_CALLBACK(jingle_rtp_codecs_changed_cb), session); g_signal_connect(G_OBJECT(media), "state-changed", G_CALLBACK(jingle_rtp_state_changed_cb), session); + g_signal_connect(G_OBJECT(media), "stream-info", + G_CALLBACK(jingle_rtp_stream_info_cb), session); g_object_unref(session); return media; diff -r c0499eb4dd4d -r d7393eebf1f4 libpurple/protocols/jabber/libxmpp.c --- a/libpurple/protocols/jabber/libxmpp.c Mon Mar 23 01:43:21 2009 +0000 +++ b/libpurple/protocols/jabber/libxmpp.c Mon Mar 23 01:43:25 2009 +0000 @@ -119,13 +119,8 @@ jabber_attention_types, /* attention_types */ sizeof(PurplePluginProtocolInfo), /* struct_size */ NULL, /* get_account_text_table */ -#ifdef USE_VV jabber_initiate_media, /* initiate_media */ jabber_get_media_caps, /* get_media_caps */ -#else - NULL, /* initiate_media */ - NULL /* can_do_media */ -#endif }; static gboolean load_plugin(PurplePlugin *plugin) diff -r c0499eb4dd4d -r d7393eebf1f4 libpurple/protocols/msn/notification.c --- a/libpurple/protocols/msn/notification.c Mon Mar 23 01:43:21 2009 +0000 +++ b/libpurple/protocols/msn/notification.c Mon Mar 23 01:43:25 2009 +0000 @@ -1609,7 +1609,7 @@ if ( (root = xmlnode_from_str(cmd->payload, cmd->payload_len)) == NULL) { - purple_debug_error("msn", "Unable to parse GCF payload into a XML tree"); + purple_debug_error("msn", "Unable to parse GCF payload into a XML tree\n"); return; } @@ -1682,7 +1682,7 @@ user = msn_userlist_find_user(session->userlist, passport); if (user == NULL) { char *str = g_strndup(payload, len); - purple_debug_info("msn", "unknown user %s, payload is %s", + purple_debug_info("msn", "unknown user %s, payload is %s\n", passport, str); g_free(str); return; diff -r c0499eb4dd4d -r d7393eebf1f4 libpurple/protocols/msn/oim.c --- a/libpurple/protocols/msn/oim.c Mon Mar 23 01:43:21 2009 +0000 +++ b/libpurple/protocols/msn/oim.c Mon Mar 23 01:43:25 2009 +0000 @@ -174,7 +174,7 @@ gchar *faultcode_str = xmlnode_get_data(faultcode); if (faultcode_str && g_str_equal(faultcode_str, "q0:BadContextToken")) { - purple_debug_warning("msn", "OIM Request Error, Updating token now."); + purple_debug_warning("msn", "OIM Request Error, Updating token now.\n"); msn_nexus_update_token(data->oim->session->nexus, data->send ? MSN_AUTH_LIVE_SECURE : MSN_AUTH_MESSENGER_WEB, (GSourceFunc)msn_oim_request_helper, data); @@ -183,7 +183,7 @@ } else if (faultcode_str && g_str_equal(faultcode_str, "q0:AuthenticationFailed")) { if (xmlnode_get_child(fault, "detail/RequiredAuthPolicy") != NULL) { - purple_debug_warning("msn", "OIM Request Error, Updating token now."); + purple_debug_warning("msn", "OIM Request Error, Updating token now.\n"); msn_nexus_update_token(data->oim->session->nexus, data->send ? MSN_AUTH_LIVE_SECURE : MSN_AUTH_MESSENGER_WEB, (GSourceFunc)msn_oim_request_helper, data); diff -r c0499eb4dd4d -r d7393eebf1f4 libpurple/protocols/msn/state.c --- a/libpurple/protocols/msn/state.c Mon Mar 23 01:43:21 2009 +0000 +++ b/libpurple/protocols/msn/state.c Mon Mar 23 01:43:25 2009 +0000 @@ -169,7 +169,7 @@ } currentmediaNode = xmlnode_get_child(payloadNode, "CurrentMedia"); if (currentmediaNode == NULL) { - purple_debug_info("msn", "No CurrentMedia Node"); + purple_debug_info("msn", "No CurrentMedia Node\n"); xmlnode_free(payloadNode); return NULL; } @@ -195,7 +195,7 @@ } psmNode = xmlnode_get_child(payloadNode, "PSM"); if (psmNode == NULL) { - purple_debug_info("msn", "No PSM status Node"); + purple_debug_info("msn", "No PSM status Node\n"); xmlnode_free(payloadNode); return NULL; } diff -r c0499eb4dd4d -r d7393eebf1f4 libpurple/protocols/msn/switchboard.c --- a/libpurple/protocols/msn/switchboard.c Mon Mar 23 01:43:21 2009 +0000 +++ b/libpurple/protocols/msn/switchboard.c Mon Mar 23 01:43:25 2009 +0000 @@ -590,7 +590,7 @@ payload = msn_message_gen_payload(msg, &payload_len); #ifdef MSN_DEBUG_SB - purple_debug_info("msn", "SB length:{%" G_GSIZE_FORMAT "}", payload_len); + purple_debug_info("msn", "SB length:{%" G_GSIZE_FORMAT "}\n", payload_len); msn_message_show_readable(msg, "SB SEND", FALSE); #endif diff -r c0499eb4dd4d -r d7393eebf1f4 libpurple/protocols/msn/userlist.c --- a/libpurple/protocols/msn/userlist.c Mon Mar 23 01:43:21 2009 +0000 +++ b/libpurple/protocols/msn/userlist.c Mon Mar 23 01:43:25 2009 +0000 @@ -858,7 +858,7 @@ } if ( (user = msn_userlist_find_user(userlist, who)) == NULL) { - purple_debug_error("msn", "User %s not found!", who); + purple_debug_error("msn", "User %s not found!\n", who); return FALSE; } @@ -887,7 +887,7 @@ } if ( (user = msn_userlist_find_user(userlist, who)) == NULL) { - purple_debug_error("msn", "User %s not found!", who); + purple_debug_error("msn", "User %s not found!\n", who); return FALSE; } diff -r c0499eb4dd4d -r d7393eebf1f4 libpurple/util.c --- a/libpurple/util.c Mon Mar 23 01:43:21 2009 +0000 +++ b/libpurple/util.c Mon Mar 23 01:43:25 2009 +0000 @@ -4044,6 +4044,13 @@ &gfud->website.page, &gfud->website.user, &gfud->website.passwd); if (purple_strcasestr(url, "https://") != NULL) { + if (!purple_ssl_is_supported()) { + purple_util_fetch_url_error(gfud, + _("Unable to connect to %s: Server requires TLS/SSL, but no TLS/SSL support was found."), + gfud->website.address); + return NULL; + } + gfud->is_ssl = TRUE; gfud->ssl_connection = purple_ssl_connect(NULL, gfud->website.address, gfud->website.port, diff -r c0499eb4dd4d -r d7393eebf1f4 pidgin/gtkconn.c diff -r c0499eb4dd4d -r d7393eebf1f4 pidgin/gtkmedia.c --- a/pidgin/gtkmedia.c Mon Mar 23 01:43:21 2009 +0000 +++ b/pidgin/gtkmedia.c Mon Mar 23 01:43:25 2009 +0000 @@ -324,7 +324,7 @@ if (message->type != GST_MESSAGE_ELEMENT) return TRUE; - if (gst_structure_has_name( + if (!gst_structure_has_name( gst_message_get_structure(message), "level")) return TRUE; @@ -612,6 +612,10 @@ gtk_widget_show(gtkmedia->priv->recv_progress); } if (type & PURPLE_MEDIA_SEND_AUDIO) { + GstElement *media_src = purple_media_get_src(media, sid); + gtkmedia->priv->send_level = gst_bin_get_by_name( + GST_BIN(media_src), "sendlevel"); + gtkmedia->priv->send_progress = gtk_progress_bar_new(); gtk_widget_set_size_request(gtkmedia->priv->send_progress, 320, 10); gtk_box_pack_end(GTK_BOX(send_widget), @@ -656,25 +660,49 @@ } static void -pidgin_media_state_changed_cb(PurpleMedia *media, - PurpleMediaStateChangedType type, +pidgin_media_state_changed_cb(PurpleMedia *media, PurpleMediaState state, gchar *sid, gchar *name, PidginMedia *gtkmedia) { - purple_debug_info("gtkmedia", "type: %d sid: %s name: %s\n", - type, sid, name); + purple_debug_info("gtkmedia", "state: %d sid: %s name: %s\n", + state, sid, name); if (sid == NULL && name == NULL) { - if (type == PURPLE_MEDIA_STATE_CHANGED_END) { + if (state == PURPLE_MEDIA_STATE_END) { pidgin_media_emit_message(gtkmedia, _("The call has been terminated.")); gtk_widget_destroy(GTK_WIDGET(gtkmedia)); - - } else if (type == PURPLE_MEDIA_STATE_CHANGED_REJECTED) { - pidgin_media_emit_message(gtkmedia, - _("You have rejected the call.")); } - } else if (type == PURPLE_MEDIA_STATE_CHANGED_NEW && + } else if (state == PURPLE_MEDIA_STATE_NEW && sid != NULL && name != NULL) { pidgin_media_ready_cb(media, gtkmedia, sid); + } else if (state == PURPLE_MEDIA_STATE_CONNECTED && + purple_media_get_session_type(media, sid) & + PURPLE_MEDIA_RECV_AUDIO) { + GstElement *tee = purple_media_get_tee(media, sid, name); + GstIterator *iter = gst_element_iterate_src_pads(tee); + GstPad *sinkpad; + if (gst_iterator_next(iter, (gpointer)&sinkpad) + == GST_ITERATOR_OK) { + GstPad *peer = gst_pad_get_peer(sinkpad); + if (peer != NULL) { + gtkmedia->priv->recv_level = + gst_bin_get_by_name( + GST_BIN(GST_OBJECT_PARENT( + peer)), "recvlevel"); + gst_object_unref(peer); + } + gst_object_unref(sinkpad); + } + gst_iterator_free(iter); + } +} + +static void +pidgin_media_stream_info_cb(PurpleMedia *media, PurpleMediaInfoType type, + gchar *sid, gchar *name, PidginMedia *gtkmedia) +{ + if (type == PURPLE_MEDIA_INFO_REJECT) { + pidgin_media_emit_message(gtkmedia, + _("You have rejected the call.")); } } @@ -707,6 +735,8 @@ G_CALLBACK(pidgin_media_accepted_cb), media); g_signal_connect(G_OBJECT(media->priv->media), "state-changed", G_CALLBACK(pidgin_media_state_changed_cb), media); + g_signal_connect(G_OBJECT(media->priv->media), "stream-info", + G_CALLBACK(pidgin_media_stream_info_cb), media); break; } case PROP_SCREENNAME: @@ -806,33 +836,105 @@ static GstElement * create_default_video_src(void) { - GstElement *ret = NULL; - purple_media_video_init_src(&ret); - return ret; + GstElement *sendbin, *src, *videoscale, *capsfilter; + GstPad *pad; + GstPad *ghost; + GstCaps *caps; + const gchar *video_plugin = purple_prefs_get_string( + "/purple/media/video/plugin"); + const gchar *video_device = purple_prefs_get_string( + "/purple/media/video/device"); + + sendbin = gst_bin_new("purplesendvideobin"); + src = gst_element_factory_make(video_plugin, "purplevideosource"); + videoscale = gst_element_factory_make("videoscale", NULL); + capsfilter = gst_element_factory_make("capsfilter", NULL); + + /* It was recommended to set the size < 352x288 and framerate < 20 */ + caps = gst_caps_from_string("video/x-raw-yuv , width=[250,350] , " + "height=[200,275] , framerate=[10/1,20/1]"); + g_object_set(G_OBJECT(capsfilter), "caps", caps, NULL); + + gst_bin_add_many(GST_BIN(sendbin), src, + videoscale, capsfilter, NULL); + gst_element_link_many(src, videoscale, capsfilter, NULL); + + if (!strcmp(video_plugin, "videotestsrc")) { + /* Set is-live to true to throttle videotestsrc */ + g_object_set (G_OBJECT(src), "is-live", TRUE, NULL); + } + + pad = gst_element_get_static_pad(capsfilter, "src"); + ghost = gst_ghost_pad_new("ghostsrc", pad); + gst_object_unref(pad); + gst_element_add_pad(sendbin, ghost); + + if (video_device != NULL && strcmp(video_device, "")) + g_object_set(G_OBJECT(src), "device", video_device, NULL); + + return sendbin; } static GstElement * create_default_video_sink(void) { - GstElement *ret = NULL; - purple_media_video_init_recv(&ret); - return ret; + return gst_element_factory_make("autovideosink", NULL); } static GstElement * create_default_audio_src(void) { - GstElement *ret = NULL, *level = NULL; - purple_media_audio_init_src(&ret, &level); - return ret; + GstElement *bin, *src, *volume, *level; + GstPad *pad, *ghost; + const gchar *audio_device = purple_prefs_get_string( + "/purple/media/audio/device"); + double input_volume = purple_prefs_get_int( + "/purple/media/audio/volume/input")/10.0; + + bin = gst_bin_new("purplesendaudiobin"); + src = gst_element_factory_make("alsasrc", "asrc"); + volume = gst_element_factory_make("volume", "purpleaudioinputvolume"); + g_object_set(volume, "volume", input_volume, NULL); + level = gst_element_factory_make("level", "sendlevel"); + gst_bin_add_many(GST_BIN(bin), src, volume, level, NULL); + gst_element_link(src, volume); + gst_element_link(volume, level); + pad = gst_element_get_pad(level, "src"); + ghost = gst_ghost_pad_new("ghostsrc", pad); + gst_element_add_pad(bin, ghost); + g_object_set(G_OBJECT(level), "message", TRUE, NULL); + + if (audio_device != NULL && strcmp(audio_device, "")) + g_object_set(G_OBJECT(src), "device", audio_device, NULL); + + return bin; } static GstElement * create_default_audio_sink(void) { - GstElement *ret = NULL, *level = NULL; - purple_media_audio_init_recv(&ret, &level); - return ret; + GstElement *bin, *sink, *volume, *level, *queue; + GstPad *pad, *ghost; + double output_volume = purple_prefs_get_int( + "/purple/media/audio/volume/output")/10.0; + + bin = gst_bin_new("pidginrecvaudiobin"); + sink = gst_element_factory_make("alsasink", "asink"); + g_object_set(G_OBJECT(sink), "async", FALSE, "sync", FALSE, NULL); + volume = gst_element_factory_make("volume", "purpleaudiooutputvolume"); + g_object_set(volume, "volume", output_volume, NULL); + level = gst_element_factory_make("level", "recvlevel"); + queue = gst_element_factory_make("queue", NULL); + gst_bin_add_many(GST_BIN(bin), sink, volume, level, queue, NULL); + gst_element_link(level, sink); + gst_element_link(volume, level); + gst_element_link(queue, volume); + pad = gst_element_get_pad(queue, "sink"); + ghost = gst_ghost_pad_new("ghostsink", pad); + gst_element_add_pad(bin, ghost); + g_object_set(G_OBJECT(level), "message", TRUE, NULL); + + return bin; } static PurpleMediaElementInfo default_video_src = diff -r c0499eb4dd4d -r d7393eebf1f4 pidgin/gtknotify.c --- a/pidgin/gtknotify.c Mon Mar 23 01:43:21 2009 +0000 +++ b/pidgin/gtknotify.c Mon Mar 23 01:43:25 2009 +0000 @@ -28,6 +28,7 @@ #include +#include "account.h" #include "connection.h" #include "debug.h" #include "prefs.h" @@ -37,6 +38,7 @@ #include "gtkblist.h" #include "gtkimhtml.h" #include "gtknotify.h" +#include "gtkpounce.h" #include "gtkutils.h" typedef struct @@ -57,6 +59,13 @@ typedef struct { PurpleAccount *account; + PurplePounce *pounce; +} PidginNotifyPounceData; + + +typedef struct +{ + PurpleAccount *account; GtkListStore *model; GtkWidget *treeview; GtkWidget *window; @@ -80,21 +89,44 @@ COLUMNS_PIDGIN_MAIL }; -typedef struct _PidginMailDialog PidginMailDialog; +enum +{ + PIDGIN_POUNCE_ICON, + PIDGIN_POUNCE_ALIAS, + PIDGIN_POUNCE_EVENT, + PIDGIN_POUNCE_TEXT, + PIDGIN_POUNCE_DATE, + PIDGIN_POUNCE_DATA, + PIDGIN_POUNCE_COLUMNS +}; -struct _PidginMailDialog +typedef struct _PidginNotifyDialog PidginNotifyDialog; +typedef PidginNotifyDialog PidginMailDialog; + +struct _PidginNotifyDialog { GtkWidget *dialog; GtkWidget *treeview; GtkTreeStore *treemodel; GtkLabel *label; GtkWidget *open_button; + GtkWidget *dismiss_button; + GtkWidget *edit_button; int total_count; gboolean in_use; }; -static PidginMailDialog *mail_dialog = NULL; +typedef enum +{ + PIDGIN_NOTIFY_MAIL, + PIDGIN_NOTIFY_POUNCE, + PIDGIN_NOTIFY_TYPES +} PidginNotifyType; +static PidginNotifyDialog *mail_dialog = NULL; +static PidginNotifyDialog *pounce_dialog = NULL; + +static GtkWidget *pidgin_get_notification_dialog(PidginNotifyType type); static void *pidgin_notify_emails(PurpleConnection *gc, size_t count, gboolean detailed, const char **subjects, const char **froms, const char **tos, @@ -109,6 +141,159 @@ } static void +pounce_response_close(PidginNotifyDialog *dialog) +{ + GtkTreeIter iter; + PidginNotifyPounceData *pounce_data; + + while (gtk_tree_model_get_iter_first( + GTK_TREE_MODEL(pounce_dialog->treemodel), &iter)) { + gtk_tree_model_get(GTK_TREE_MODEL(pounce_dialog->treemodel), &iter, + PIDGIN_POUNCE_DATA, &pounce_data, + -1); + gtk_tree_store_remove(dialog->treemodel, &iter); + + g_free(pounce_data); + } + + gtk_widget_destroy(pounce_dialog->dialog); + g_free(pounce_dialog); + pounce_dialog = NULL; +} + +static void +delete_foreach(GtkTreeModel *model, GtkTreePath *path, + GtkTreeIter *iter, gpointer data) +{ + PidginNotifyPounceData *pounce_data; + + gtk_tree_model_get(model, iter, + PIDGIN_POUNCE_DATA, &pounce_data, + -1); + + if (pounce_data != NULL) + g_free(pounce_data); +} + +static void +append_to_list(GtkTreeModel *model, GtkTreePath *path, + GtkTreeIter *iter, gpointer data) +{ + GList **list = data; + *list = g_list_prepend(*list, gtk_tree_path_copy(path)); +} +static void +pounce_response_dismiss() +{ + GtkTreeSelection *selection; + GList *list = NULL; + + selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(pounce_dialog->treeview)); + gtk_tree_selection_selected_foreach(selection, delete_foreach, pounce_dialog); + gtk_tree_selection_selected_foreach(selection, append_to_list, &list); + + while (list) { + GtkTreeIter iter; + if (gtk_tree_model_get_iter(GTK_TREE_MODEL(pounce_dialog->treemodel), &iter, + list->data)) { + gtk_tree_store_remove(GTK_TREE_STORE(pounce_dialog->treemodel), &iter); + } + gtk_tree_path_free(list->data); + list = g_list_delete_link(list, list); + } +} + +static void +pounce_response_edit_cb(GtkTreeModel *model, GtkTreePath *path, + GtkTreeIter *iter, gpointer data) +{ + PidginNotifyPounceData *pounce_data; + PidginNotifyDialog *dialog = (PidginNotifyDialog*)data; + PurplePounce *pounce; + GList *list; + + list = purple_pounces_get_all(); + + gtk_tree_model_get(GTK_TREE_MODEL(dialog->treemodel), iter, + PIDGIN_POUNCE_DATA, &pounce_data, + -1); + + for (; list != NULL; list = list->next) { + pounce = list->data; + if (pounce == pounce_data->pounce) { + pidgin_pounce_editor_show(pounce_data->account, NULL, pounce_data->pounce); + return; + } + } + + purple_debug_warning("gtknotify", "Pounce was destroyed.\n"); +} + +static void +pounce_response_cb(GtkDialog *dlg, gint id, PidginNotifyDialog *dialog) +{ + GtkTreeSelection *selection = NULL; + + switch (id) { + case GTK_RESPONSE_CLOSE: + case GTK_RESPONSE_DELETE_EVENT: + pounce_response_close(dialog); + break; + case GTK_RESPONSE_NO: + pounce_response_dismiss(); + break; + case GTK_RESPONSE_APPLY: + selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dialog->treeview)); + gtk_tree_selection_selected_foreach(selection, pounce_response_edit_cb, + dialog); + break; + } +} + +static void +pounce_row_selected_cb(GtkTreeView *tv, GtkTreePath *path, + GtkTreeViewColumn *col, gpointer data) +{ + GtkTreeIter iter; + GtkTreeSelection *selection; + gboolean selected; + GList *list; + + selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(pounce_dialog->treeview)); + + selected = gtk_tree_selection_get_selected(selection, + NULL, &iter); + + if (selected) { + PurplePounce *pounce; + PidginNotifyPounceData *pounce_data; + + list = purple_pounces_get_all(); + + gtk_tree_model_get(GTK_TREE_MODEL(pounce_dialog->treemodel), &iter, + PIDGIN_POUNCE_DATA, &pounce_data, + -1); + + gtk_widget_set_sensitive(pounce_dialog->edit_button, FALSE); + + for (; list != NULL; list = list->next) { + pounce = list->data; + if (pounce == pounce_data->pounce) { + gtk_widget_set_sensitive(pounce_dialog->edit_button, TRUE); + break; + } + } + + gtk_widget_set_sensitive(pounce_dialog->dismiss_button, TRUE); + } else { + gtk_widget_set_sensitive(pounce_dialog->edit_button, FALSE); + gtk_widget_set_sensitive(pounce_dialog->dismiss_button, FALSE); + } + + +} + +static void email_response_cb(GtkDialog *dlg, gint id, PidginMailDialog *dialog) { PidginNotifyMailData *data = NULL; @@ -342,89 +527,7 @@ static GtkWidget * pidgin_get_mail_dialog(void) { - if (mail_dialog == NULL) { - GtkWidget *dialog = NULL; - GtkWidget *label; - GtkWidget *sw; - GtkCellRenderer *rend; - GtkTreeViewColumn *column; - GtkWidget *button = NULL; - GtkWidget *vbox = NULL; - - dialog = gtk_dialog_new_with_buttons(_("New Mail"), NULL, 0, - GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, - NULL); - gtk_window_set_role(GTK_WINDOW(dialog), "new_mail_detailed"); - g_signal_connect(G_OBJECT(dialog), "focus-in-event", - G_CALLBACK(mail_window_focus_cb), NULL); - - gtk_dialog_add_button(GTK_DIALOG(dialog), - _("Open All Messages"), GTK_RESPONSE_ACCEPT); - - button = gtk_dialog_add_button(GTK_DIALOG(dialog), - PIDGIN_STOCK_OPEN_MAIL, GTK_RESPONSE_YES); - - /* make "Open All Messages" the default response */ - gtk_dialog_set_default_response(GTK_DIALOG(dialog), - GTK_RESPONSE_ACCEPT); - - /* Setup the dialog */ - gtk_container_set_border_width(GTK_CONTAINER(dialog), PIDGIN_HIG_BOX_SPACE); - gtk_container_set_border_width(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), PIDGIN_HIG_BOX_SPACE); - gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE); - gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(dialog)->vbox), PIDGIN_HIG_BORDER); - - /* Vertical box */ - vbox = GTK_DIALOG(dialog)->vbox; - - /* Golden ratio it up! */ - gtk_widget_set_size_request(dialog, 550, 400); - - sw = gtk_scrolled_window_new(NULL, NULL); - gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_IN); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); - - mail_dialog = g_new0(PidginMailDialog, 1); - mail_dialog->dialog = dialog; - mail_dialog->open_button = button; - - mail_dialog->treemodel = gtk_tree_store_new(COLUMNS_PIDGIN_MAIL, - GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_POINTER); - mail_dialog->treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(mail_dialog->treemodel)); - g_object_unref(G_OBJECT(mail_dialog->treemodel)); - gtk_tree_view_set_search_column(GTK_TREE_VIEW(mail_dialog->treeview), PIDGIN_MAIL_TEXT); - gtk_tree_view_set_search_equal_func(GTK_TREE_VIEW(mail_dialog->treeview), - pidgin_tree_view_search_equal_func, NULL, NULL); - - g_signal_connect(G_OBJECT(dialog), "response", - G_CALLBACK(email_response_cb), mail_dialog); - g_signal_connect(G_OBJECT(gtk_tree_view_get_selection(GTK_TREE_VIEW(mail_dialog->treeview))), - "changed", G_CALLBACK(selection_changed_cb), mail_dialog); - g_signal_connect(G_OBJECT(mail_dialog->treeview), "row-activated", G_CALLBACK(email_row_activated_cb), NULL); - - gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(mail_dialog->treeview), FALSE); - gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(mail_dialog->treeview), TRUE); - gtk_container_add(GTK_CONTAINER(sw), mail_dialog->treeview); - - column = gtk_tree_view_column_new(); - gtk_tree_view_column_set_resizable(column, TRUE); - rend = gtk_cell_renderer_pixbuf_new(); - gtk_tree_view_column_pack_start(column, rend, FALSE); - gtk_tree_view_column_set_attributes(column, rend, "pixbuf", PIDGIN_MAIL_ICON, NULL); - rend = gtk_cell_renderer_text_new(); - gtk_tree_view_column_pack_start(column, rend, TRUE); - gtk_tree_view_column_set_attributes(column, rend, "markup", PIDGIN_MAIL_TEXT, NULL); - gtk_tree_view_append_column(GTK_TREE_VIEW(mail_dialog->treeview), column); - - label = gtk_label_new(NULL); - gtk_label_set_markup(GTK_LABEL(label), _("You have mail!")); - gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); - gtk_misc_set_alignment(GTK_MISC(label), 0, 0); - gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); - gtk_box_pack_start(GTK_BOX(vbox), sw, TRUE, TRUE, 0); - } - - return mail_dialog->dialog; + return pidgin_get_notification_dialog(PIDGIN_NOTIFY_MAIL); } /* count == 0 means this is a detailed mail notification. @@ -1001,8 +1104,10 @@ { PidginNotifyMailData *data = (PidginNotifyMailData *)ui_handle; - g_free(data->url); - g_free(data); + if (data) { + g_free(data->url); + g_free(data); + } } else if (type == PURPLE_NOTIFY_SEARCHRESULTS) { @@ -1234,6 +1339,228 @@ return NULL; } +static GtkWidget * +pidgin_get_dialog(PidginNotifyType type, GtkTreeStore *treemodel) +{ + GtkWidget *dialog = NULL; + GtkWidget *label = NULL; + GtkWidget *sw; + GtkCellRenderer *rend; + GtkTreeViewColumn *column; + GtkWidget *button = NULL; + GtkWidget *vbox = NULL; + GtkTreeSelection *sel; + PidginNotifyDialog *spec_dialog = NULL; + + g_return_val_if_fail(type < PIDGIN_NOTIFY_TYPES, NULL); + + dialog = gtk_dialog_new_with_buttons(NULL, NULL, 0, + GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, + NULL); + + /* Setup the dialog */ + gtk_container_set_border_width(GTK_CONTAINER(dialog), PIDGIN_HIG_BOX_SPACE); + gtk_container_set_border_width(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), PIDGIN_HIG_BOX_SPACE); + gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE); + gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(dialog)->vbox), PIDGIN_HIG_BORDER); + + /* Vertical box */ + vbox = GTK_DIALOG(dialog)->vbox; + + /* Golden ratio it up! */ + gtk_widget_set_size_request(dialog, 550, 400); + + sw = gtk_scrolled_window_new(NULL, NULL); + gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_IN); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); + + spec_dialog = g_new0(PidginNotifyDialog, 1); + spec_dialog->dialog = dialog; + spec_dialog->open_button = button; + + spec_dialog->treemodel = treemodel; + spec_dialog->treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(spec_dialog->treemodel)); + g_object_unref(G_OBJECT(spec_dialog->treemodel)); + + gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(spec_dialog->treeview), TRUE); + gtk_container_add(GTK_CONTAINER(sw), spec_dialog->treeview); + + if (type == PIDGIN_NOTIFY_MAIL) { + gtk_window_set_title(GTK_WINDOW(dialog), _("New Mail")); + gtk_window_set_role(GTK_WINDOW(dialog), "new_mail_detailed"); + g_signal_connect(G_OBJECT(dialog), "focus-in-event", + G_CALLBACK(mail_window_focus_cb), NULL); + + gtk_dialog_add_button(GTK_DIALOG(dialog), + _("Open All Messages"), GTK_RESPONSE_ACCEPT); + + button = gtk_dialog_add_button(GTK_DIALOG(dialog), + PIDGIN_STOCK_OPEN_MAIL, GTK_RESPONSE_YES); + + gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(spec_dialog->treeview), FALSE); + + gtk_tree_view_set_search_column(GTK_TREE_VIEW(spec_dialog->treeview), PIDGIN_MAIL_TEXT); + gtk_tree_view_set_search_equal_func(GTK_TREE_VIEW(spec_dialog->treeview), + pidgin_tree_view_search_equal_func, NULL, NULL); + + g_signal_connect(G_OBJECT(dialog), "response", + G_CALLBACK(email_response_cb), spec_dialog); + g_signal_connect(G_OBJECT(gtk_tree_view_get_selection(GTK_TREE_VIEW(spec_dialog->treeview))), + "changed", G_CALLBACK(selection_changed_cb), spec_dialog); + g_signal_connect(G_OBJECT(spec_dialog->treeview), "row-activated", G_CALLBACK(email_row_activated_cb), NULL); + + column = gtk_tree_view_column_new(); + gtk_tree_view_column_set_resizable(column, TRUE); + rend = gtk_cell_renderer_pixbuf_new(); + gtk_tree_view_column_pack_start(column, rend, FALSE); + + gtk_tree_view_column_set_attributes(column, rend, "pixbuf", PIDGIN_MAIL_ICON, NULL); + rend = gtk_cell_renderer_text_new(); + gtk_tree_view_column_pack_start(column, rend, TRUE); + gtk_tree_view_column_set_attributes(column, rend, "markup", PIDGIN_MAIL_TEXT, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(spec_dialog->treeview), column); + + label = gtk_label_new(NULL); + gtk_label_set_markup(GTK_LABEL(label), _("You have mail!")); + + } else if (type == PIDGIN_NOTIFY_POUNCE) { + gtk_window_set_title(GTK_WINDOW(dialog), _("New Pounces")); + + button = gtk_dialog_add_button(GTK_DIALOG(dialog), + _("Dismiss"), GTK_RESPONSE_NO); + gtk_widget_set_sensitive(button, FALSE); + spec_dialog->dismiss_button = button; + + button = gtk_dialog_add_button(GTK_DIALOG(dialog), + PIDGIN_STOCK_EDIT, GTK_RESPONSE_APPLY); + gtk_widget_set_sensitive(button, FALSE); + spec_dialog->edit_button = button; + + g_signal_connect(G_OBJECT(dialog), "response", + G_CALLBACK(pounce_response_cb), spec_dialog); + + column = gtk_tree_view_column_new(); + gtk_tree_view_column_set_title(column, _("Buddy")); + gtk_tree_view_column_set_resizable(column, TRUE); + rend = gtk_cell_renderer_pixbuf_new(); + gtk_tree_view_column_pack_start(column, rend, FALSE); + + gtk_tree_view_column_set_attributes(column, rend, "pixbuf", PIDGIN_POUNCE_ICON, NULL); + rend = gtk_cell_renderer_text_new(); + gtk_tree_view_column_pack_start(column, rend, FALSE); + gtk_tree_view_column_add_attribute(column, rend, "text", PIDGIN_POUNCE_ALIAS); + gtk_tree_view_append_column(GTK_TREE_VIEW(spec_dialog->treeview), column); + + column = gtk_tree_view_column_new(); + gtk_tree_view_column_set_title(column, _("Event")); + gtk_tree_view_column_set_resizable(column, TRUE); + rend = gtk_cell_renderer_text_new(); + gtk_tree_view_column_pack_start(column, rend, FALSE); + gtk_tree_view_column_add_attribute(column, rend, "text", PIDGIN_POUNCE_EVENT); + gtk_tree_view_append_column(GTK_TREE_VIEW(spec_dialog->treeview), column); + + column = gtk_tree_view_column_new(); + gtk_tree_view_column_set_title(column, _("Message")); + gtk_tree_view_column_set_resizable(column, TRUE); + rend = gtk_cell_renderer_text_new(); + gtk_tree_view_column_pack_start(column, rend, FALSE); + gtk_tree_view_column_add_attribute(column, rend, "text", PIDGIN_POUNCE_TEXT); + gtk_tree_view_append_column(GTK_TREE_VIEW(spec_dialog->treeview), column); + + column = gtk_tree_view_column_new(); + gtk_tree_view_column_set_title(column, _("Date")); + gtk_tree_view_column_set_resizable(column, TRUE); + rend = gtk_cell_renderer_text_new(); + gtk_tree_view_column_pack_start(column, rend, FALSE); + gtk_tree_view_column_add_attribute(column, rend, "text", PIDGIN_POUNCE_DATE); + gtk_tree_view_append_column(GTK_TREE_VIEW(spec_dialog->treeview), column); + + label = gtk_label_new(NULL); + gtk_label_set_markup(GTK_LABEL(label), _("You have pounced!")); + + sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(spec_dialog->treeview)); + gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE); + g_signal_connect(G_OBJECT(sel), "changed", + G_CALLBACK(pounce_row_selected_cb), NULL); + } + + gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); + gtk_misc_set_alignment(GTK_MISC(label), 0, 0); + gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(vbox), sw, TRUE, TRUE, 2); + + if (type == PIDGIN_NOTIFY_MAIL) + mail_dialog = spec_dialog; + else if (type == PIDGIN_NOTIFY_POUNCE) { + pounce_dialog = spec_dialog; + } + + return spec_dialog->dialog; + +} + +void +pidgin_notify_pounce_add(PurpleAccount *account, PurplePounce *pounce, + const char *alias, const char *event, const char *message, const char *date) +{ + GtkWidget *dialog; + GdkPixbuf *icon; + GtkTreeIter iter; + PidginNotifyPounceData *pounce_data; + + dialog = pidgin_get_notification_dialog(PIDGIN_NOTIFY_POUNCE); + + icon = pidgin_create_prpl_icon(account, PIDGIN_PRPL_ICON_SMALL); + + pounce_data = g_new(PidginNotifyPounceData, 1); + + pounce_data->account = account; + pounce_data->pounce = pounce; + + gtk_tree_store_append(pounce_dialog->treemodel, &iter, NULL); + + gtk_tree_store_set(pounce_dialog->treemodel, &iter, + PIDGIN_POUNCE_ICON, icon, + PIDGIN_POUNCE_ALIAS, alias, + PIDGIN_POUNCE_EVENT, event, + PIDGIN_POUNCE_TEXT, (message != NULL)? message : _("No message"), + PIDGIN_POUNCE_DATE, date, + PIDGIN_POUNCE_DATA, pounce_data, + -1); + + if (icon) + g_object_unref(icon); + + gtk_widget_show_all(dialog); + + return; +} + +static GtkWidget * +pidgin_get_notification_dialog(PidginNotifyType type) +{ + GtkTreeStore *model = NULL; + + if (type == PIDGIN_NOTIFY_MAIL) { + if (mail_dialog != NULL) + return mail_dialog->dialog; + + model = gtk_tree_store_new(COLUMNS_PIDGIN_MAIL, + GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_POINTER); + + } else if (type == PIDGIN_NOTIFY_POUNCE) { + + if (pounce_dialog != NULL) + return pounce_dialog->dialog; + + model = gtk_tree_store_new(PIDGIN_POUNCE_COLUMNS, + GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, + G_TYPE_STRING, G_TYPE_POINTER); + } + + return pidgin_get_dialog(type, model); +} + static PurpleNotifyUiOps ops = { pidgin_notify_message, diff -r c0499eb4dd4d -r d7393eebf1f4 pidgin/gtknotify.h --- a/pidgin/gtknotify.h Mon Mar 23 01:43:21 2009 +0000 +++ b/pidgin/gtknotify.h Mon Mar 23 01:43:25 2009 +0000 @@ -27,6 +27,18 @@ #define _PIDGINNOTIFY_H_ #include "notify.h" +#include "pounce.h" + +/** + * Adds a buddy pounce to the buddy pounce dialog + * + * @param alias The buddy alias + * @param event Event description + * @param message Pounce message + * @param date Pounce date + */ +void pidgin_notify_pounce_add(PurpleAccount *account, PurplePounce *pounce, + const char *alias, const char *event, const char *message, const char *date); /** * Returns the UI operations structure for GTK+ notification functions. diff -r c0499eb4dd4d -r d7393eebf1f4 pidgin/gtkpounce.c --- a/pidgin/gtkpounce.c Mon Mar 23 01:43:21 2009 +0000 +++ b/pidgin/gtkpounce.c Mon Mar 23 01:43:25 2009 +0000 @@ -30,7 +30,6 @@ #include "account.h" #include "conversation.h" #include "debug.h" -#include "notify.h" #include "prpl.h" #include "request.h" #include "server.h" @@ -41,6 +40,7 @@ #include "gtkdialogs.h" #include "gtkimhtml.h" #include "gtkpounce.h" +#include "gtknotify.h" #include "pidginstock.h" #include "gtkutils.h" @@ -1275,7 +1275,6 @@ /* Handle double-clicking */ g_signal_connect(G_OBJECT(treeview), "button_press_event", G_CALLBACK(pounce_double_click_cb), dialog); - gtk_container_add(GTK_CONTAINER(sw), treeview); gtk_widget_show(treeview); @@ -1458,27 +1457,27 @@ */ tmp = g_strdup_printf( (events & PURPLE_POUNCE_TYPING) ? - _("%s has started typing to you (%s)") : + _("Started typing") : (events & PURPLE_POUNCE_TYPED) ? - _("%s has paused while typing to you (%s)") : + _("Paused while typing") : (events & PURPLE_POUNCE_SIGNON) ? - _("%s has signed on (%s)") : + _("Signed on") : (events & PURPLE_POUNCE_IDLE_RETURN) ? - _("%s has returned from being idle (%s)") : + _("Returned from being idle") : (events & PURPLE_POUNCE_AWAY_RETURN) ? - _("%s has returned from being away (%s)") : + _("Returned from being away") : (events & PURPLE_POUNCE_TYPING_STOPPED) ? - _("%s has stopped typing to you (%s)") : + _("Stopped typing") : (events & PURPLE_POUNCE_SIGNOFF) ? - _("%s has signed off (%s)") : + _("Signed off") : (events & PURPLE_POUNCE_IDLE) ? - _("%s has become idle (%s)") : + _("Became idle") : (events & PURPLE_POUNCE_AWAY) ? - _("%s has gone away. (%s)") : + _("Went away") : (events & PURPLE_POUNCE_MESSAGE_RECEIVED) ? - _("%s has sent you a message. (%s)") : - _("Unknown pounce event. Please report this!"), - alias, purple_account_get_protocol_name(account)); + _("Sent a message") : + _("Unknown.... Please report this!") + ); /* * Ok here is where I change the second argument, title, from @@ -1488,16 +1487,9 @@ if ((name_shown = purple_account_get_alias(account)) == NULL) name_shown = purple_account_get_username(account); - if (reason == NULL) - { - purple_notify_info(NULL, name_shown, tmp, purple_date_format_full(NULL)); - } - else - { - char *tmp2 = g_strdup_printf("%s\n\n%s", reason, purple_date_format_full(NULL)); - purple_notify_info(NULL, name_shown, tmp, tmp2); - g_free(tmp2); - } + pidgin_notify_pounce_add(account, pounce, alias, tmp, reason, + purple_date_format_full(NULL)); + g_free(tmp); } diff -r c0499eb4dd4d -r d7393eebf1f4 pidgin/gtkprefs.c --- a/pidgin/gtkprefs.c Mon Mar 23 01:43:21 2009 +0000 +++ b/pidgin/gtkprefs.c Mon Mar 23 01:43:25 2009 +0000 @@ -57,6 +57,10 @@ #include "gtkutils.h" #include "pidginstock.h" +#ifdef USE_VV +#include +#endif + #define PROXYHOST 0 #define PROXYPORT 1 #define PROXYUSER 2 @@ -2401,13 +2405,97 @@ } #ifdef USE_VV +static GList* +get_devices(const gchar *plugin) +{ + GObjectClass *klass; + GstPropertyProbe *probe; + const GParamSpec *pspec; + GstElement *element = gst_element_factory_make(plugin, NULL); + GstElementFactory *factory; + const gchar *longname = NULL; + GList *ret = NULL; + + if (element == NULL) + return NULL; + + factory = gst_element_get_factory(element); + + longname = gst_element_factory_get_longname(factory); + klass = G_OBJECT_GET_CLASS(element); + + if (!g_object_class_find_property(klass, "device") || + !GST_IS_PROPERTY_PROBE(element) || + !(probe = GST_PROPERTY_PROBE(element)) || + !(pspec = gst_property_probe_get_property(probe, + "device"))) { + purple_debug_info("media", + "Found source '%s' (%s) - no device\n", + longname, GST_PLUGIN_FEATURE (factory)->name); + } else { + gint n; + gchar *name; + GValueArray *array; + + purple_debug_info("media", "Found devices\n"); + + /* Set autoprobe[-fps] to FALSE to avoid delays when probing. */ + if (g_object_class_find_property (klass, "autoprobe")) { + g_object_set(G_OBJECT (element), + "autoprobe", FALSE, NULL); + if (g_object_class_find_property(klass, + "autoprobe-fps")) { + g_object_set(G_OBJECT(element), + "autoprobe-fps", FALSE, NULL); + } + } + + array = gst_property_probe_probe_and_get_values(probe, pspec); + if (array != NULL) { + for (n = 0 ; n < array->n_values ; n++) { + GValue *device = g_value_array_get_nth( + array, n); + + ret = g_list_append(ret, + g_value_dup_string(device)); + + g_object_set(G_OBJECT(element), "device", + g_value_get_string(device), + NULL); + g_object_get(G_OBJECT(element), + "device-name", &name, NULL); + purple_debug_info("media", "Found source '%s'" + " (%s) - device '%s' (%s)\n", + longname, GST_PLUGIN_FEATURE( + factory)->name, name, + g_value_get_string(device)); + g_free(name); + } + g_value_array_free(array); + } + + /* Restore autoprobe[-fps] to TRUE. */ + if (g_object_class_find_property(klass, "autoprobe")) { + g_object_set(G_OBJECT(element), + "autoprobe", TRUE, NULL); + if (g_object_class_find_property(klass, + "autoprobe-fps")) { + g_object_set(G_OBJECT(element), + "autoprobe-fps", TRUE, NULL); + } + } + } + + gst_object_unref(element); + return ret; +} /* get a GList of pairs name / device */ static GList * get_device_items(const gchar *plugin) { GList *ret = NULL; - GList *devices = purple_media_get_devices(plugin); + GList *devices = get_devices(plugin); GstElement *element = gst_element_factory_make(plugin, NULL); if (element == NULL)