Add list parameter to all buddy list UI ops.
[pidgin-git.git] / finch / gntmedia.c
blob4e874bf1d9f9c1aae1b38ebc7d5d09850014a336
1 /* finch
3 * Finch is the legal property of its developers, whose names are too numerous
4 * to list here. Please refer to the COPYRIGHT file distributed with this
5 * source distribution.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
22 #include <internal.h>
23 #include "finch.h"
24 #include "gntconv.h"
25 #include "gntmedia.h"
27 #include "gnt.h"
28 #include "gntbutton.h"
29 #include "gntbox.h"
30 #include "gntlabel.h"
32 #include "cmds.h"
33 #include "conversation.h"
34 #include "debug.h"
35 #include "mediamanager.h"
37 /* An incredibly large part of the following is from gtkmedia.c */
38 #ifdef USE_VV
39 #include "media-gst.h"
41 #undef hangup
43 #define FINCH_TYPE_MEDIA (finch_media_get_type())
44 #define FINCH_MEDIA(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), FINCH_TYPE_MEDIA, FinchMedia))
45 #define FINCH_MEDIA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), FINCH_TYPE_MEDIA, FinchMediaClass))
46 #define FINCH_IS_MEDIA(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), FINCH_TYPE_MEDIA))
47 #define FINCH_IS_MEDIA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), FINCH_TYPE_MEDIA))
48 #define FINCH_MEDIA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), FINCH_TYPE_MEDIA, FinchMediaClass))
50 typedef struct _FinchMedia FinchMedia;
51 typedef struct _FinchMediaClass FinchMediaClass;
52 typedef struct _FinchMediaPrivate FinchMediaPrivate;
53 typedef enum _FinchMediaState FinchMediaState;
55 struct _FinchMediaClass
57 GntBoxClass parent_class;
60 struct _FinchMedia
62 GntBox parent;
63 FinchMediaPrivate *priv;
66 struct _FinchMediaPrivate
68 PurpleMedia *media;
70 GntWidget *accept;
71 GntWidget *reject;
72 GntWidget *hangup;
73 GntWidget *calling;
75 PurpleConversation *conv;
78 static GType finch_media_get_type (void);
79 static void finch_media_class_init (FinchMediaClass *klass);
80 static void finch_media_init (FinchMedia *media);
81 static void finch_media_finalize (GObject *object);
82 static void finch_media_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
83 static void finch_media_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
85 enum {
86 MESSAGE,
87 LAST_SIGNAL
89 static guint finch_media_signals[LAST_SIGNAL] = {0};
91 enum {
92 PROP_0,
93 PROP_MEDIA,
96 G_DEFINE_TYPE_WITH_PRIVATE(FinchMedia, finch_media, GNT_TYPE_BOX);
98 static void
99 finch_media_class_init (FinchMediaClass *klass)
101 GObjectClass *gobject_class = (GObjectClass*)klass;
103 gobject_class->finalize = finch_media_finalize;
104 gobject_class->set_property = finch_media_set_property;
105 gobject_class->get_property = finch_media_get_property;
107 g_object_class_install_property(gobject_class, PROP_MEDIA,
108 g_param_spec_object("media",
109 "PurpleMedia",
110 "The PurpleMedia associated with this media.",
111 PURPLE_TYPE_MEDIA,
112 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
114 finch_media_signals[MESSAGE] = g_signal_new("message", G_TYPE_FROM_CLASS(klass),
115 G_SIGNAL_RUN_LAST, 0, NULL, NULL,
116 g_cclosure_marshal_VOID__STRING,
117 G_TYPE_NONE, 1, G_TYPE_STRING);
121 static void
122 finch_media_init (FinchMedia *media)
124 media->priv = finch_media_get_instance_private(media);
126 media->priv->calling = gnt_label_new(_("Calling..."));
127 media->priv->hangup = gnt_button_new(_("Hangup"));
128 media->priv->accept = gnt_button_new(_("Accept"));
129 media->priv->reject = gnt_button_new(_("Reject"));
131 gnt_box_set_alignment(GNT_BOX(media), GNT_ALIGN_MID);
133 gnt_box_add_widget(GNT_BOX(media), media->priv->accept);
134 gnt_box_add_widget(GNT_BOX(media), media->priv->reject);
137 static void
138 finch_media_finalize (GObject *media)
140 FinchMedia *gntmedia = FINCH_MEDIA(media);
141 purple_debug_info("gntmedia", "finch_media_finalize\n");
142 if (gntmedia->priv->media)
143 g_object_unref(gntmedia->priv->media);
146 static void
147 finch_media_emit_message(FinchMedia *gntmedia, const char *msg)
149 g_signal_emit(gntmedia, finch_media_signals[MESSAGE], 0, msg);
152 static void
153 finch_media_connected_cb(PurpleMedia *media, FinchMedia *gntmedia)
155 GntWidget *parent;
157 finch_media_emit_message(gntmedia, _("Call in progress."));
159 gnt_box_remove(GNT_BOX(gntmedia), gntmedia->priv->accept);
160 gnt_box_remove(GNT_BOX(gntmedia), gntmedia->priv->reject);
161 gnt_box_remove(GNT_BOX(gntmedia), gntmedia->priv->hangup);
162 gnt_box_remove(GNT_BOX(gntmedia), gntmedia->priv->calling);
164 gnt_box_add_widget(GNT_BOX(gntmedia), gntmedia->priv->hangup);
166 gnt_widget_destroy(gntmedia->priv->accept);
167 gnt_widget_destroy(gntmedia->priv->reject);
168 gnt_widget_destroy(gntmedia->priv->calling);
169 gntmedia->priv->accept = NULL;
170 gntmedia->priv->reject = NULL;
171 gntmedia->priv->calling = NULL;
173 parent = gnt_widget_get_toplevel(GNT_WIDGET(gntmedia));
174 gnt_box_readjust(GNT_BOX(parent));
175 gnt_widget_draw(parent);
178 static void
179 finch_media_wait_cb(PurpleMedia *media, FinchMedia *gntmedia)
181 GntWidget *parent;
183 gnt_box_remove(GNT_BOX(gntmedia), gntmedia->priv->accept);
184 gnt_box_remove(GNT_BOX(gntmedia), gntmedia->priv->reject);
185 gnt_box_remove(GNT_BOX(gntmedia), gntmedia->priv->hangup);
186 gnt_box_remove(GNT_BOX(gntmedia), gntmedia->priv->calling);
188 gnt_box_add_widget(GNT_BOX(gntmedia), gntmedia->priv->calling);
189 gnt_box_add_widget(GNT_BOX(gntmedia), gntmedia->priv->hangup);
191 parent = gnt_widget_get_toplevel(GNT_WIDGET(gntmedia));
192 gnt_box_readjust(GNT_BOX(parent));
193 gnt_widget_draw(parent);
196 static void
197 finch_media_state_changed_cb(PurpleMedia *media, PurpleMediaState state,
198 gchar *sid, gchar *name, FinchMedia *gntmedia)
200 purple_debug_info("gntmedia", "state: %d sid: %s name: %s\n",
201 state, sid, name);
202 if (sid == NULL && name == NULL) {
203 if (state == PURPLE_MEDIA_STATE_END) {
204 finch_media_emit_message(gntmedia,
205 _("The call has been terminated."));
206 finch_conversation_set_info_widget(
207 gntmedia->priv->conv, NULL);
208 gnt_widget_destroy(GNT_WIDGET(gntmedia));
210 * XXX: This shouldn't have to be here
211 * to free the FinchMedia widget.
213 g_object_unref(gntmedia);
215 } else if (state == PURPLE_MEDIA_STATE_CONNECTED) {
216 finch_media_connected_cb(media, gntmedia);
217 } else if (state == PURPLE_MEDIA_STATE_NEW &&
218 sid != NULL && name != NULL &&
219 purple_media_is_initiator(media, sid, name) == FALSE) {
220 PurpleAccount *account;
221 PurpleBuddy *buddy;
222 const gchar *alias;
223 PurpleMediaSessionType type =
224 purple_media_get_session_type(media, sid);
225 gchar *message = NULL;
227 account = purple_media_get_account(gntmedia->priv->media);
228 buddy = purple_blist_find_buddy(account, name);
229 alias = buddy ? purple_buddy_get_contact_alias(buddy) : name;
231 if (type & PURPLE_MEDIA_AUDIO) {
232 message = g_strdup_printf(
233 _("%s wishes to start an audio session with you."),
234 alias);
235 } else {
236 message = g_strdup_printf(
237 _("%s is trying to start an unsupported media session type with you."),
238 alias);
240 finch_media_emit_message(gntmedia, message);
241 g_free(message);
245 static void
246 finch_media_stream_info_cb(PurpleMedia *media, PurpleMediaInfoType type,
247 gchar *sid, gchar *name, gboolean local, FinchMedia *gntmedia)
249 if (type == PURPLE_MEDIA_INFO_REJECT) {
250 finch_media_emit_message(gntmedia,
251 _("You have rejected the call."));
255 static void
256 finch_media_accept_cb(PurpleMedia *media, GntWidget *widget)
258 purple_media_stream_info(media, PURPLE_MEDIA_INFO_ACCEPT,
259 NULL, NULL, TRUE);
262 static void
263 finch_media_hangup_cb(PurpleMedia *media, GntWidget *widget)
265 purple_media_stream_info(media, PURPLE_MEDIA_INFO_HANGUP,
266 NULL, NULL, TRUE);
269 static void
270 finch_media_reject_cb(PurpleMedia *media, GntWidget *widget)
272 purple_media_stream_info(media, PURPLE_MEDIA_INFO_REJECT,
273 NULL, NULL, TRUE);
276 static void
277 finch_media_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
279 FinchMedia *media;
280 g_return_if_fail(FINCH_IS_MEDIA(object));
282 media = FINCH_MEDIA(object);
283 switch (prop_id) {
284 case PROP_MEDIA:
286 if (media->priv->media)
287 g_object_unref(media->priv->media);
288 media->priv->media = g_value_dup_object(value);
289 g_signal_connect_swapped(G_OBJECT(media->priv->accept), "activate",
290 G_CALLBACK(finch_media_accept_cb), media->priv->media);
291 g_signal_connect_swapped(G_OBJECT(media->priv->reject), "activate",
292 G_CALLBACK(finch_media_reject_cb), media->priv->media);
293 g_signal_connect_swapped(G_OBJECT(media->priv->hangup), "activate",
294 G_CALLBACK(finch_media_hangup_cb), media->priv->media);
296 if (purple_media_is_initiator(media->priv->media,
297 NULL, NULL) == TRUE) {
298 finch_media_wait_cb(media->priv->media, media);
300 g_signal_connect(G_OBJECT(media->priv->media), "state-changed",
301 G_CALLBACK(finch_media_state_changed_cb), media);
302 g_signal_connect(G_OBJECT(media->priv->media), "stream-info",
303 G_CALLBACK(finch_media_stream_info_cb), media);
304 break;
306 default:
307 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
308 break;
312 static void
313 finch_media_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
315 FinchMedia *media;
316 g_return_if_fail(FINCH_IS_MEDIA(object));
318 media = FINCH_MEDIA(object);
320 switch (prop_id) {
321 case PROP_MEDIA:
322 g_value_set_object(value, media->priv->media);
323 break;
324 default:
325 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
326 break;
330 static GntWidget *
331 finch_media_new(PurpleMedia *media)
333 return GNT_WIDGET(g_object_new(finch_media_get_type(),
334 "media", media,
335 "vertical", FALSE,
336 "homogeneous", FALSE,
337 NULL));
340 static void
341 gntmedia_message_cb(FinchMedia *gntmedia, const char *msg, PurpleConversation *conv)
343 if (PURPLE_IS_IM_CONVERSATION(conv)) {
344 purple_conversation_write_system_message(conv, msg, 0);
348 static gboolean
349 finch_new_media(PurpleMediaManager *manager, PurpleMedia *media,
350 PurpleAccount *account, gchar *name, gpointer null)
352 GntWidget *gntmedia;
353 PurpleConversation *conv;
355 conv = PURPLE_CONVERSATION(purple_im_conversation_new(account, name));
357 gntmedia = finch_media_new(media);
358 g_signal_connect(G_OBJECT(gntmedia), "message", G_CALLBACK(gntmedia_message_cb), conv);
359 FINCH_MEDIA(gntmedia)->priv->conv = conv;
360 finch_conversation_set_info_widget(conv, gntmedia);
361 return TRUE;
364 static PurpleCmdRet
365 call_cmd_cb(PurpleConversation *conv, const char *cmd, char **args,
366 char **eror, gpointer data)
368 PurpleAccount *account = purple_conversation_get_account(conv);
370 if (!purple_protocol_initiate_media(account,
371 purple_conversation_get_name(conv),
372 PURPLE_MEDIA_AUDIO))
373 return PURPLE_CMD_RET_FAILED;
375 return PURPLE_CMD_RET_OK;
378 #endif /* USE_VV */
380 void finch_media_manager_init(void)
382 #ifdef USE_VV
383 PurpleMediaManager *manager = purple_media_manager_get();
384 PurpleMediaElementInfo *audio_src = NULL;
385 PurpleMediaElementInfo *audio_sink = NULL;
386 const char *pref;
388 pref = purple_prefs_get_string(
389 FINCH_PREFS_ROOT "/vvconfig/audio/src/device");
390 if (pref)
391 audio_src = purple_media_manager_get_element_info(manager, pref);
392 if (!audio_src) {
393 pref = "autoaudiosrc";
394 purple_prefs_set_string(
395 FINCH_PREFS_ROOT "/vvconfig/audio/src/device", pref);
396 audio_src = purple_media_manager_get_element_info(manager,
397 pref);
400 pref = purple_prefs_get_string(
401 FINCH_PREFS_ROOT "/vvconfig/audio/sink/device");
402 if (pref)
403 audio_sink = purple_media_manager_get_element_info(manager, pref);
404 if (!audio_sink) {
405 pref = "autoaudiosink";
406 purple_prefs_set_string(
407 FINCH_PREFS_ROOT "/vvconfig/audio/sink/device", pref);
408 audio_sink = purple_media_manager_get_element_info(manager,
409 pref);
412 g_signal_connect(G_OBJECT(manager), "init-media", G_CALLBACK(finch_new_media), NULL);
413 purple_cmd_register("call", "", PURPLE_CMD_P_DEFAULT,
414 PURPLE_CMD_FLAG_IM, NULL,
415 call_cmd_cb, _("call: Make an audio call."), NULL);
417 purple_media_manager_set_ui_caps(manager,
418 PURPLE_MEDIA_CAPS_AUDIO |
419 PURPLE_MEDIA_CAPS_AUDIO_SINGLE_DIRECTION);
421 purple_debug_info("gntmedia", "Registering media element types\n");
422 purple_media_manager_set_active_element(manager, audio_src);
423 purple_media_manager_set_active_element(manager, audio_sink);
424 #endif
427 void finch_media_manager_uninit(void)
429 #ifdef USE_VV
430 PurpleMediaManager *manager = purple_media_manager_get();
431 g_signal_handlers_disconnect_by_func(G_OBJECT(manager),
432 G_CALLBACK(finch_new_media), NULL);
433 #endif