Clear audio_output when the call ends
[empathy-mirror.git] / libempathy-gtk / empathy-individual-menu.c
bloba92e5bcd980b97911fc6437003a756d2220b2bd6
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * Copyright (C) 2008-2010 Collabora Ltd.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 * Authors: Xavier Claessens <xclaesse@gmail.com>
20 * Travis Reitter <travis.reitter@collabora.co.uk>
23 #include "config.h"
25 #include <string.h>
27 #include <glib/gi18n-lib.h>
28 #include <gtk/gtk.h>
29 #include <telepathy-glib/util.h>
31 #include <folks/folks.h>
32 #include <folks/folks-telepathy.h>
34 #include <libempathy/empathy-request-util.h>
35 #include <libempathy/empathy-individual-manager.h>
36 #include <libempathy/empathy-chatroom-manager.h>
37 #include <libempathy/empathy-utils.h>
39 #include "empathy-individual-menu.h"
40 #include "empathy-images.h"
41 #include "empathy-log-window.h"
42 #include "empathy-contact-dialogs.h"
43 #include "empathy-gtk-enum-types.h"
44 #include "empathy-individual-edit-dialog.h"
45 #include "empathy-individual-information-dialog.h"
46 #include "empathy-ui-utils.h"
47 #include "empathy-share-my-desktop.h"
48 #include "empathy-linking-dialog.h"
49 #include "empathy-call-utils.h"
51 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyIndividualMenu)
53 typedef struct {
54 FolksIndividual *individual; /* owned */
55 EmpathyIndividualFeatureFlags features;
56 } EmpathyIndividualMenuPriv;
58 enum {
59 PROP_INDIVIDUAL = 1,
60 PROP_FEATURES,
63 enum {
64 SIGNAL_LINK_CONTACTS_ACTIVATED,
65 LAST_SIGNAL
68 static guint signals[LAST_SIGNAL];
70 G_DEFINE_TYPE (EmpathyIndividualMenu, empathy_individual_menu, GTK_TYPE_MENU);
72 static void
73 individual_menu_add_personas (GtkMenuShell *menu,
74 FolksIndividual *individual,
75 EmpathyIndividualFeatureFlags features)
77 GtkWidget *item;
78 GeeSet *personas;
79 GeeIterator *iter;
80 guint persona_count = 0;
81 gboolean c;
83 g_return_if_fail (GTK_IS_MENU (menu));
84 g_return_if_fail (FOLKS_IS_INDIVIDUAL (individual));
85 g_return_if_fail (empathy_folks_individual_contains_contact (individual));
87 personas = folks_individual_get_personas (individual);
88 /* we'll re-use this iterator throughout */
89 iter = gee_iterable_iterator (GEE_ITERABLE (personas));
91 /* Make sure we've got enough valid entries for these menu items to add
92 * functionality */
93 while (gee_iterator_next (iter))
95 FolksPersona *persona = gee_iterator_get (iter);
96 if (empathy_folks_persona_is_interesting (persona))
97 persona_count++;
99 g_clear_object (&persona);
102 /* return early if these entries would add nothing beyond the "quick" items */
103 if (persona_count <= 1)
104 return;
106 /* add a separator before the list of personas */
107 item = gtk_separator_menu_item_new ();
108 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
109 gtk_widget_show (item);
111 personas = folks_individual_get_personas (individual);
112 for (c = gee_iterator_first (iter); c; c = gee_iterator_next (iter))
114 GtkWidget *image;
115 GtkWidget *contact_item;
116 GtkWidget *contact_submenu;
117 TpContact *tp_contact;
118 EmpathyContact *contact;
119 TpfPersona *persona = gee_iterator_get (iter);
120 gchar *label;
121 FolksPersonaStore *store;
122 const gchar *account;
123 GtkWidget *action;
125 if (!empathy_folks_persona_is_interesting (FOLKS_PERSONA (persona)))
126 goto while_finish;
128 tp_contact = tpf_persona_get_contact (persona);
129 contact = empathy_contact_dup_from_tp_contact (tp_contact);
131 store = folks_persona_get_store (FOLKS_PERSONA (persona));
132 account = folks_persona_store_get_display_name (store);
134 /* Translators: this is used in the context menu for a contact. The first
135 * parameter is a contact ID (e.g. foo@jabber.org) and the second is one
136 * of the user's account IDs (e.g. me@hotmail.com). */
137 label = g_strdup_printf (_("%s (%s)"),
138 folks_persona_get_display_id (FOLKS_PERSONA (persona)), account);
140 contact_item = gtk_image_menu_item_new_with_label (label);
141 gtk_image_menu_item_set_always_show_image (GTK_IMAGE_MENU_ITEM (contact_item),
142 TRUE);
143 contact_submenu = gtk_menu_new ();
144 gtk_menu_item_set_submenu (GTK_MENU_ITEM (contact_item), contact_submenu);
145 image = gtk_image_new_from_icon_name (
146 empathy_icon_name_for_contact (contact), GTK_ICON_SIZE_MENU);
147 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (contact_item), image);
148 gtk_widget_show (image);
150 /* Chat */
151 if (features & EMPATHY_INDIVIDUAL_FEATURE_CHAT)
153 action = empathy_individual_chat_menu_item_new (NULL, contact);
154 gtk_menu_shell_append (GTK_MENU_SHELL (contact_submenu), action);
155 gtk_widget_show (action);
158 /* SMS */
159 if (features & EMPATHY_INDIVIDUAL_FEATURE_SMS)
161 action = empathy_individual_sms_menu_item_new (NULL, contact);
162 gtk_menu_shell_append (GTK_MENU_SHELL (contact_submenu), action);
163 gtk_widget_show (action);
166 if (features & EMPATHY_INDIVIDUAL_FEATURE_CALL)
168 /* Audio Call */
169 action = empathy_individual_audio_call_menu_item_new (NULL, contact);
170 gtk_menu_shell_append (GTK_MENU_SHELL (contact_submenu), action);
171 gtk_widget_show (action);
173 /* Video Call */
174 action = empathy_individual_video_call_menu_item_new (NULL, contact);
175 gtk_menu_shell_append (GTK_MENU_SHELL (contact_submenu), action);
176 gtk_widget_show (action);
179 /* Log */
180 if (features & EMPATHY_INDIVIDUAL_FEATURE_LOG)
182 action = empathy_individual_log_menu_item_new (NULL, contact);
183 gtk_menu_shell_append (GTK_MENU_SHELL (contact_submenu), action);
184 gtk_widget_show (action);
187 /* Invite */
188 action = empathy_individual_invite_menu_item_new (NULL, contact);
189 gtk_menu_shell_append (GTK_MENU_SHELL (contact_submenu), action);
190 gtk_widget_show (action);
192 /* File transfer */
193 action = empathy_individual_file_transfer_menu_item_new (NULL, contact);
194 gtk_menu_shell_append (GTK_MENU_SHELL (contact_submenu), action);
195 gtk_widget_show (action);
197 /* Share my desktop */
198 action = empathy_individual_share_my_desktop_menu_item_new (NULL,
199 contact);
200 gtk_menu_shell_append (GTK_MENU_SHELL (contact_submenu), action);
201 gtk_widget_show (action);
203 gtk_menu_shell_append (GTK_MENU_SHELL (menu), contact_item);
204 gtk_widget_show (contact_item);
206 g_free (label);
207 g_object_unref (contact);
209 while_finish:
210 g_clear_object (&persona);
213 g_clear_object (&iter);
216 static void
217 individual_link_menu_item_activate_cb (EmpathyIndividualMenu *self)
219 EmpathyIndividualMenuPriv *priv = GET_PRIV (self);
220 GtkWidget *dialog;
222 dialog = empathy_linking_dialog_show (priv->individual, NULL);
223 g_signal_emit (self, signals[SIGNAL_LINK_CONTACTS_ACTIVATED], 0, dialog);
226 static void
227 empathy_individual_menu_init (EmpathyIndividualMenu *self)
229 EmpathyIndividualMenuPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
230 EMPATHY_TYPE_INDIVIDUAL_MENU, EmpathyIndividualMenuPriv);
232 self->priv = priv;
235 static void
236 constructed (GObject *object)
238 EmpathyIndividualMenuPriv *priv = GET_PRIV (object);
239 GtkMenuShell *shell;
240 GtkWidget *item;
241 FolksIndividual *individual;
242 EmpathyIndividualFeatureFlags features;
244 /* Build the menu */
245 shell = GTK_MENU_SHELL (object);
246 individual = priv->individual;
247 features = priv->features;
249 /* Chat */
250 if (features & EMPATHY_INDIVIDUAL_FEATURE_CHAT)
252 item = empathy_individual_chat_menu_item_new (individual, NULL);
253 if (item != NULL)
255 gtk_menu_shell_append (shell, item);
256 gtk_widget_show (item);
260 /* SMS */
261 if (features & EMPATHY_INDIVIDUAL_FEATURE_SMS)
263 item = empathy_individual_sms_menu_item_new (individual, NULL);
264 if (item != NULL)
266 gtk_menu_shell_append (shell, item);
267 gtk_widget_show (item);
271 if (features & EMPATHY_INDIVIDUAL_FEATURE_CALL)
273 /* Audio Call */
274 item = empathy_individual_audio_call_menu_item_new (individual, NULL);
275 gtk_menu_shell_append (shell, item);
276 gtk_widget_show (item);
278 /* Video Call */
279 item = empathy_individual_video_call_menu_item_new (individual, NULL);
280 gtk_menu_shell_append (shell, item);
281 gtk_widget_show (item);
284 /* Log */
285 if (features & EMPATHY_INDIVIDUAL_FEATURE_LOG)
287 item = empathy_individual_log_menu_item_new (individual, NULL);
288 gtk_menu_shell_append (shell, item);
289 gtk_widget_show (item);
292 /* Invite */
293 item = empathy_individual_invite_menu_item_new (individual, NULL);
294 gtk_menu_shell_append (shell, item);
295 gtk_widget_show (item);
297 /* File transfer */
298 item = empathy_individual_file_transfer_menu_item_new (individual, NULL);
299 gtk_menu_shell_append (shell, item);
300 gtk_widget_show (item);
302 /* Share my desktop */
303 /* FIXME we should add the "Share my desktop" menu item if Vino is
304 a registered handler in MC5 */
305 item = empathy_individual_share_my_desktop_menu_item_new (individual, NULL);
306 gtk_menu_shell_append (shell, item);
307 gtk_widget_show (item);
309 /* Menu items to target specific contacts */
310 individual_menu_add_personas (GTK_MENU_SHELL (object), individual, features);
312 /* Separator */
313 if (features & (EMPATHY_INDIVIDUAL_FEATURE_EDIT |
314 EMPATHY_INDIVIDUAL_FEATURE_INFO |
315 EMPATHY_INDIVIDUAL_FEATURE_FAVOURITE |
316 EMPATHY_INDIVIDUAL_FEATURE_LINK))
318 item = gtk_separator_menu_item_new ();
319 gtk_menu_shell_append (shell, item);
320 gtk_widget_show (item);
323 /* Edit */
324 if (features & EMPATHY_INDIVIDUAL_FEATURE_EDIT)
326 item = empathy_individual_edit_menu_item_new (individual);
327 gtk_menu_shell_append (shell, item);
328 gtk_widget_show (item);
331 /* Link */
332 if (features & EMPATHY_INDIVIDUAL_FEATURE_LINK)
334 item = empathy_individual_link_menu_item_new (individual);
335 gtk_menu_shell_append (shell, item);
337 g_signal_connect_swapped (item, "activate",
338 (GCallback) individual_link_menu_item_activate_cb, object);
340 gtk_widget_show (item);
343 /* Info */
344 if (features & EMPATHY_INDIVIDUAL_FEATURE_INFO)
346 item = empathy_individual_info_menu_item_new (individual);
347 gtk_menu_shell_append (shell, item);
348 gtk_widget_show (item);
351 /* Favorite checkbox */
352 if (features & EMPATHY_INDIVIDUAL_FEATURE_FAVOURITE)
354 item = empathy_individual_favourite_menu_item_new (individual);
355 gtk_menu_shell_append (shell, item);
356 gtk_widget_show (item);
360 static void
361 get_property (GObject *object,
362 guint param_id,
363 GValue *value,
364 GParamSpec *pspec)
366 EmpathyIndividualMenuPriv *priv;
368 priv = GET_PRIV (object);
370 switch (param_id)
372 case PROP_INDIVIDUAL:
373 g_value_set_object (value, priv->individual);
374 break;
375 case PROP_FEATURES:
376 g_value_set_flags (value, priv->features);
377 break;
378 default:
379 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
380 break;
384 static void
385 set_property (GObject *object,
386 guint param_id,
387 const GValue *value,
388 GParamSpec *pspec)
390 EmpathyIndividualMenuPriv *priv;
392 priv = GET_PRIV (object);
394 switch (param_id)
396 case PROP_INDIVIDUAL:
397 priv->individual = g_value_dup_object (value);
398 break;
399 case PROP_FEATURES:
400 priv->features = g_value_get_flags (value);
401 break;
402 default:
403 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
404 break;
408 static void
409 dispose (GObject *object)
411 EmpathyIndividualMenuPriv *priv = GET_PRIV (object);
413 tp_clear_object (&priv->individual);
415 G_OBJECT_CLASS (empathy_individual_menu_parent_class)->dispose (object);
418 static void
419 empathy_individual_menu_class_init (EmpathyIndividualMenuClass *klass)
421 GObjectClass *object_class = G_OBJECT_CLASS (klass);
423 object_class->constructed = constructed;
424 object_class->get_property = get_property;
425 object_class->set_property = set_property;
426 object_class->dispose = dispose;
429 * EmpathyIndividualMenu:individual:
431 * The #FolksIndividual the menu is for.
433 g_object_class_install_property (object_class, PROP_INDIVIDUAL,
434 g_param_spec_object ("individual",
435 "Individual",
436 "The #FolksIndividual the menu is for.",
437 FOLKS_TYPE_INDIVIDUAL,
438 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
441 * EmpathyIndividualMenu:features:
443 * A set of feature flags controlling which entries are shown.
445 g_object_class_install_property (object_class, PROP_FEATURES,
446 g_param_spec_flags ("features",
447 "Features",
448 "A set of feature flags controlling which entries are shown.",
449 EMPATHY_TYPE_INDIVIDUAL_FEATURE_FLAGS,
450 EMPATHY_INDIVIDUAL_FEATURE_NONE,
451 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
453 signals[SIGNAL_LINK_CONTACTS_ACTIVATED] =
454 g_signal_new ("link-contacts-activated", G_OBJECT_CLASS_TYPE (klass),
455 G_SIGNAL_RUN_LAST, 0, NULL, NULL,
456 g_cclosure_marshal_VOID__OBJECT,
457 G_TYPE_NONE, 1, EMPATHY_TYPE_LINKING_DIALOG);
459 g_type_class_add_private (object_class, sizeof (EmpathyIndividualMenuPriv));
462 GtkWidget *
463 empathy_individual_menu_new (FolksIndividual *individual,
464 EmpathyIndividualFeatureFlags features)
466 g_return_val_if_fail (FOLKS_IS_INDIVIDUAL (individual), NULL);
467 g_return_val_if_fail (features != EMPATHY_INDIVIDUAL_FEATURE_NONE, NULL);
469 return g_object_new (EMPATHY_TYPE_INDIVIDUAL_MENU,
470 "individual", individual,
471 "features", features,
472 NULL);
475 /* Like menu_item_set_first_contact(), but always operates upon the given
476 * contact. If the contact is non-NULL, it is assumed that the menu entry should
477 * be sensitive. */
478 static gboolean
479 menu_item_set_contact (GtkWidget *item,
480 EmpathyContact *contact,
481 GCallback activate_callback,
482 EmpathyActionType action_type)
484 gboolean can_do_action = FALSE;
486 if (contact != NULL)
487 can_do_action = empathy_contact_can_do_action (contact, action_type);
488 gtk_widget_set_sensitive (item, can_do_action);
490 if (can_do_action == TRUE)
492 /* We want to make sure that the EmpathyContact stays alive while the
493 * signal is connected. */
494 g_signal_connect_data (item, "activate", G_CALLBACK (activate_callback),
495 g_object_ref (contact), (GClosureNotify) g_object_unref, 0);
498 return can_do_action;
502 * Set the given menu @item to call @activate_callback using the TpContact
503 * (associated with @individual) with the highest availability who is also valid
504 * whenever @item is activated.
506 * @action_type is the type of action performed by the menu entry; this is used
507 * so that only contacts which can perform that action (e.g. are capable of
508 * receiving video calls) are selected, as appropriate.
510 static GtkWidget *
511 menu_item_set_first_contact (GtkWidget *item,
512 FolksIndividual *individual,
513 GCallback activate_callback,
514 EmpathyActionType action_type)
516 EmpathyContact *best_contact;
518 best_contact = empathy_contact_dup_best_for_action (individual, action_type);
519 menu_item_set_contact (item, best_contact, G_CALLBACK (activate_callback),
520 action_type);
521 tp_clear_object (&best_contact);
523 return item;
526 static void
527 empathy_individual_chat_menu_item_activated (GtkMenuItem *item,
528 EmpathyContact *contact)
530 g_return_if_fail (EMPATHY_IS_CONTACT (contact));
532 empathy_chat_with_contact (contact, empathy_get_current_action_time ());
535 GtkWidget *
536 empathy_individual_chat_menu_item_new (FolksIndividual *individual,
537 EmpathyContact *contact)
539 GtkWidget *item;
540 GtkWidget *image;
542 g_return_val_if_fail ((FOLKS_IS_INDIVIDUAL (individual) &&
543 empathy_folks_individual_contains_contact (individual)) ||
544 EMPATHY_IS_CONTACT (contact),
545 NULL);
547 item = gtk_image_menu_item_new_with_mnemonic (_("_Chat"));
548 image = gtk_image_new_from_icon_name (EMPATHY_IMAGE_MESSAGE,
549 GTK_ICON_SIZE_MENU);
550 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
551 gtk_widget_show (image);
553 if (contact != NULL)
555 menu_item_set_contact (item, contact,
556 G_CALLBACK (empathy_individual_chat_menu_item_activated),
557 EMPATHY_ACTION_CHAT);
559 else
561 menu_item_set_first_contact (item, individual,
562 G_CALLBACK (empathy_individual_chat_menu_item_activated),
563 EMPATHY_ACTION_CHAT);
566 return item;
569 static void
570 empathy_individual_sms_menu_item_activated (GtkMenuItem *item,
571 EmpathyContact *contact)
573 g_return_if_fail (EMPATHY_IS_CONTACT (contact));
575 empathy_sms_contact_id (
576 empathy_contact_get_account (contact),
577 empathy_contact_get_id (contact),
578 empathy_get_current_action_time ());
581 GtkWidget *
582 empathy_individual_sms_menu_item_new (FolksIndividual *individual,
583 EmpathyContact *contact)
585 GtkWidget *item;
586 GtkWidget *image;
588 g_return_val_if_fail ((FOLKS_IS_INDIVIDUAL (individual) &&
589 empathy_folks_individual_contains_contact (individual)) ||
590 EMPATHY_IS_CONTACT (contact),
591 NULL);
593 item = gtk_image_menu_item_new_with_mnemonic (_("_SMS"));
594 image = gtk_image_new_from_icon_name (EMPATHY_IMAGE_SMS,
595 GTK_ICON_SIZE_MENU);
596 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
597 gtk_widget_show (image);
599 if (contact != NULL)
601 menu_item_set_contact (item, contact,
602 G_CALLBACK (empathy_individual_sms_menu_item_activated),
603 EMPATHY_ACTION_SMS);
605 else
607 menu_item_set_first_contact (item, individual,
608 G_CALLBACK (empathy_individual_sms_menu_item_activated),
609 EMPATHY_ACTION_SMS);
612 return item;
615 static void
616 empathy_individual_audio_call_menu_item_activated (GtkMenuItem *item,
617 EmpathyContact *contact)
619 g_return_if_fail (EMPATHY_IS_CONTACT (contact));
621 empathy_call_new_with_streams (empathy_contact_get_id (contact),
622 empathy_contact_get_account (contact),
623 TRUE, FALSE,
624 empathy_get_current_action_time ());
627 GtkWidget *
628 empathy_individual_audio_call_menu_item_new (FolksIndividual *individual,
629 EmpathyContact *contact)
631 GtkWidget *item;
632 GtkWidget *image;
634 g_return_val_if_fail (FOLKS_IS_INDIVIDUAL (individual) ||
635 EMPATHY_IS_CONTACT (contact),
636 NULL);
638 item = gtk_image_menu_item_new_with_mnemonic (C_("menu item", "_Audio Call"));
639 image = gtk_image_new_from_icon_name (EMPATHY_IMAGE_VOIP, GTK_ICON_SIZE_MENU);
640 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
641 gtk_widget_show (image);
643 if (contact != NULL)
645 menu_item_set_contact (item, contact,
646 G_CALLBACK (empathy_individual_audio_call_menu_item_activated),
647 EMPATHY_ACTION_AUDIO_CALL);
649 else
651 menu_item_set_first_contact (item, individual,
652 G_CALLBACK (empathy_individual_audio_call_menu_item_activated),
653 EMPATHY_ACTION_AUDIO_CALL);
656 return item;
659 static void
660 empathy_individual_video_call_menu_item_activated (GtkMenuItem *item,
661 EmpathyContact *contact)
663 g_return_if_fail (EMPATHY_IS_CONTACT (contact));
665 empathy_call_new_with_streams (empathy_contact_get_id (contact),
666 empathy_contact_get_account (contact),
667 TRUE, TRUE,
668 empathy_get_current_action_time ());
671 GtkWidget *
672 empathy_individual_video_call_menu_item_new (FolksIndividual *individual,
673 EmpathyContact *contact)
675 GtkWidget *item;
676 GtkWidget *image;
678 g_return_val_if_fail (FOLKS_IS_INDIVIDUAL (individual) ||
679 EMPATHY_IS_CONTACT (contact),
680 NULL);
682 item = gtk_image_menu_item_new_with_mnemonic (C_("menu item", "_Video Call"));
683 image = gtk_image_new_from_icon_name (EMPATHY_IMAGE_VIDEO_CALL,
684 GTK_ICON_SIZE_MENU);
685 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
686 gtk_widget_show (image);
688 if (contact != NULL)
690 menu_item_set_contact (item, contact,
691 G_CALLBACK (empathy_individual_video_call_menu_item_activated),
692 EMPATHY_ACTION_VIDEO_CALL);
694 else
696 menu_item_set_first_contact (item, individual,
697 G_CALLBACK (empathy_individual_video_call_menu_item_activated),
698 EMPATHY_ACTION_VIDEO_CALL);
701 return item;
704 static void
705 empathy_individual_log_menu_item_activated (GtkMenuItem *item,
706 EmpathyContact *contact)
708 g_return_if_fail (EMPATHY_IS_CONTACT (contact));
710 empathy_log_window_show (empathy_contact_get_account (contact),
711 empathy_contact_get_id (contact), FALSE, NULL);
714 GtkWidget *
715 empathy_individual_log_menu_item_new (FolksIndividual *individual,
716 EmpathyContact *contact)
718 GtkWidget *item;
719 GtkWidget *image;
721 g_return_val_if_fail (FOLKS_IS_INDIVIDUAL (individual) ||
722 EMPATHY_IS_CONTACT (contact),
723 NULL);
725 item = gtk_image_menu_item_new_with_mnemonic (_("_Previous Conversations"));
726 image = gtk_image_new_from_icon_name (EMPATHY_IMAGE_LOG, GTK_ICON_SIZE_MENU);
727 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
728 gtk_widget_show (image);
730 if (contact != NULL)
732 menu_item_set_contact (item, contact,
733 G_CALLBACK (empathy_individual_log_menu_item_activated),
734 EMPATHY_ACTION_VIEW_LOGS);
736 else
738 menu_item_set_first_contact (item, individual,
739 G_CALLBACK (empathy_individual_log_menu_item_activated),
740 EMPATHY_ACTION_VIEW_LOGS);
743 return item;
746 static void
747 empathy_individual_file_transfer_menu_item_activated (GtkMenuItem *item,
748 EmpathyContact *contact)
750 g_return_if_fail (EMPATHY_IS_CONTACT (contact));
752 empathy_send_file_with_file_chooser (contact);
755 GtkWidget *
756 empathy_individual_file_transfer_menu_item_new (FolksIndividual *individual,
757 EmpathyContact *contact)
759 GtkWidget *item;
760 GtkWidget *image;
762 g_return_val_if_fail (FOLKS_IS_INDIVIDUAL (individual) ||
763 EMPATHY_IS_CONTACT (contact),
764 NULL);
766 item = gtk_image_menu_item_new_with_mnemonic (_("Send File"));
767 image = gtk_image_new_from_icon_name (EMPATHY_IMAGE_DOCUMENT_SEND,
768 GTK_ICON_SIZE_MENU);
769 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
770 gtk_widget_show (image);
772 if (contact != NULL)
774 menu_item_set_contact (item, contact,
775 G_CALLBACK (empathy_individual_file_transfer_menu_item_activated),
776 EMPATHY_ACTION_SEND_FILE);
778 else
780 menu_item_set_first_contact (item, individual,
781 G_CALLBACK (empathy_individual_file_transfer_menu_item_activated),
782 EMPATHY_ACTION_SEND_FILE);
785 return item;
788 static void
789 empathy_individual_share_my_desktop_menu_item_activated (GtkMenuItem *item,
790 EmpathyContact *contact)
792 g_return_if_fail (EMPATHY_IS_CONTACT (contact));
794 empathy_share_my_desktop_share_with_contact (contact);
797 GtkWidget *
798 empathy_individual_share_my_desktop_menu_item_new (FolksIndividual *individual,
799 EmpathyContact *contact)
801 GtkWidget *item;
802 GtkWidget *image;
804 g_return_val_if_fail (FOLKS_IS_INDIVIDUAL (individual) ||
805 EMPATHY_IS_CONTACT (contact),
806 NULL);
808 item = gtk_image_menu_item_new_with_mnemonic (_("Share My Desktop"));
809 image = gtk_image_new_from_icon_name (GTK_STOCK_NETWORK, GTK_ICON_SIZE_MENU);
810 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
811 gtk_widget_show (image);
813 if (contact != NULL)
815 menu_item_set_contact (item, contact,
816 G_CALLBACK (empathy_individual_share_my_desktop_menu_item_activated),
817 EMPATHY_ACTION_SHARE_MY_DESKTOP);
819 else
821 menu_item_set_first_contact (item, individual,
822 G_CALLBACK (empathy_individual_share_my_desktop_menu_item_activated),
823 EMPATHY_ACTION_SHARE_MY_DESKTOP);
826 return item;
829 static void
830 favourite_menu_item_toggled_cb (GtkCheckMenuItem *item,
831 FolksIndividual *individual)
833 folks_favourite_details_set_is_favourite (
834 FOLKS_FAVOURITE_DETAILS (individual),
835 gtk_check_menu_item_get_active (item));
838 GtkWidget *
839 empathy_individual_favourite_menu_item_new (FolksIndividual *individual)
841 GtkWidget *item;
843 item = gtk_check_menu_item_new_with_label (_("Favorite"));
845 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item),
846 folks_favourite_details_get_is_favourite (
847 FOLKS_FAVOURITE_DETAILS (individual)));
849 g_signal_connect (item, "toggled",
850 G_CALLBACK (favourite_menu_item_toggled_cb), individual);
852 return item;
855 static void
856 individual_info_menu_item_activate_cb (FolksIndividual *individual)
858 empathy_individual_information_dialog_show (individual, NULL);
861 GtkWidget *
862 empathy_individual_info_menu_item_new (FolksIndividual *individual)
864 GtkWidget *item;
865 GtkWidget *image;
867 g_return_val_if_fail (FOLKS_IS_INDIVIDUAL (individual), NULL);
868 g_return_val_if_fail (empathy_folks_individual_contains_contact (individual),
869 NULL);
871 item = gtk_image_menu_item_new_with_mnemonic (_("Infor_mation"));
872 image = gtk_image_new_from_icon_name (EMPATHY_IMAGE_CONTACT_INFORMATION,
873 GTK_ICON_SIZE_MENU);
874 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
875 gtk_widget_show (image);
877 g_signal_connect_swapped (item, "activate",
878 G_CALLBACK (individual_info_menu_item_activate_cb),
879 individual);
881 return item;
884 static void
885 individual_edit_menu_item_activate_cb (FolksIndividual *individual)
887 empathy_individual_edit_dialog_show (individual, NULL);
890 GtkWidget *
891 empathy_individual_edit_menu_item_new (FolksIndividual *individual)
893 EmpathyIndividualManager *manager;
894 GtkWidget *item;
895 GtkWidget *image;
896 gboolean enable = FALSE;
897 EmpathyContact *contact;
899 g_return_val_if_fail (FOLKS_IS_INDIVIDUAL (individual), NULL);
901 contact = empathy_contact_dup_from_folks_individual (individual);
903 g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL);
905 if (empathy_individual_manager_initialized ())
907 TpConnection *connection;
909 manager = empathy_individual_manager_dup_singleton ();
910 connection = empathy_contact_get_connection (contact);
912 enable = (empathy_connection_can_alias_personas (connection) &&
913 empathy_connection_can_group_personas (connection));
915 g_object_unref (manager);
918 item = gtk_image_menu_item_new_with_mnemonic (
919 C_("Edit individual (contextual menu)", "_Edit"));
920 image = gtk_image_new_from_icon_name (GTK_STOCK_EDIT, GTK_ICON_SIZE_MENU);
921 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
922 gtk_widget_show (image);
924 gtk_widget_set_sensitive (item, enable);
926 g_signal_connect_swapped (item, "activate",
927 G_CALLBACK (individual_edit_menu_item_activate_cb), individual);
929 g_object_unref (contact);
931 return item;
934 GtkWidget *
935 empathy_individual_link_menu_item_new (FolksIndividual *individual)
937 GtkWidget *item;
938 /*GtkWidget *image;*/
940 g_return_val_if_fail (FOLKS_IS_INDIVIDUAL (individual), NULL);
942 item = gtk_image_menu_item_new_with_mnemonic (
943 /* Translators: this is a verb meaning "to connect two contacts together
944 * to form a meta-contact". */
945 C_("Link individual (contextual menu)", "_Link Contacts…"));
946 /* TODO */
947 /*image = gtk_image_new_from_icon_name (GTK_STOCK_EDIT, GTK_ICON_SIZE_MENU);
948 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
949 gtk_widget_show (image);*/
951 /* Only allow trusted Individuals to be linked */
952 gtk_widget_set_sensitive (item,
953 folks_individual_get_trust_level (individual) ==
954 FOLKS_TRUST_LEVEL_PERSONAS);
956 return item;
959 typedef struct
961 FolksIndividual *individual;
962 EmpathyContact *contact;
963 EmpathyChatroom *chatroom;
964 } RoomSubMenuData;
966 static RoomSubMenuData *
967 room_sub_menu_data_new (FolksIndividual *individual,
968 EmpathyContact *contact,
969 EmpathyChatroom *chatroom)
971 RoomSubMenuData *data;
973 data = g_slice_new0 (RoomSubMenuData);
974 if (individual != NULL)
975 data->individual = g_object_ref (individual);
976 if (contact != NULL)
977 data->contact = g_object_ref (contact);
978 data->chatroom = g_object_ref (chatroom);
980 return data;
983 static void
984 room_sub_menu_data_free (RoomSubMenuData *data)
986 tp_clear_object (&data->individual);
987 tp_clear_object (&data->contact);
988 g_object_unref (data->chatroom);
989 g_slice_free (RoomSubMenuData, data);
992 static void
993 room_sub_menu_activate_cb (GtkWidget *item,
994 RoomSubMenuData *data)
996 EmpathyTpChat *chat;
997 EmpathyChatroomManager *mgr;
998 EmpathyContact *contact = NULL;
1000 chat = empathy_chatroom_get_tp_chat (data->chatroom);
1001 if (chat == NULL)
1003 /* channel was invalidated. Ignoring */
1004 return;
1007 mgr = empathy_chatroom_manager_dup_singleton (NULL);
1009 if (data->contact != NULL)
1010 contact = g_object_ref (data->contact);
1011 else
1013 GeeSet *personas;
1014 GeeIterator *iter;
1016 /* find the first of this Individual's contacts who can join this room */
1017 personas = folks_individual_get_personas (data->individual);
1019 iter = gee_iterable_iterator (GEE_ITERABLE (personas));
1020 while (gee_iterator_next (iter) && (contact == NULL))
1022 TpfPersona *persona = gee_iterator_get (iter);
1023 TpContact *tp_contact;
1024 GList *rooms;
1026 if (empathy_folks_persona_is_interesting (FOLKS_PERSONA (persona)))
1028 tp_contact = tpf_persona_get_contact (persona);
1029 contact = empathy_contact_dup_from_tp_contact (tp_contact);
1031 rooms = empathy_chatroom_manager_get_chatrooms (mgr,
1032 empathy_contact_get_account (contact));
1034 if (g_list_find (rooms, data->chatroom) == NULL)
1035 g_clear_object (&contact);
1037 /* if contact != NULL here, we've found our match */
1039 g_list_free (rooms);
1041 g_clear_object (&persona);
1043 g_clear_object (&iter);
1046 g_object_unref (mgr);
1048 if (contact == NULL)
1050 /* contact disappeared. Ignoring */
1051 goto out;
1054 g_return_if_fail (EMPATHY_IS_CONTACT (contact));
1056 /* send invitation */
1057 empathy_contact_list_add (EMPATHY_CONTACT_LIST (chat),
1058 contact, _("Inviting you to this room"));
1060 out:
1061 g_object_unref (contact);
1064 static GtkWidget *
1065 create_room_sub_menu (FolksIndividual *individual,
1066 EmpathyContact *contact,
1067 EmpathyChatroom *chatroom)
1069 GtkWidget *item;
1070 RoomSubMenuData *data;
1072 item = gtk_menu_item_new_with_label (empathy_chatroom_get_name (chatroom));
1073 data = room_sub_menu_data_new (individual, contact, chatroom);
1074 g_signal_connect_data (item, "activate",
1075 G_CALLBACK (room_sub_menu_activate_cb), data,
1076 (GClosureNotify) room_sub_menu_data_free, 0);
1078 return item;
1081 GtkWidget *
1082 empathy_individual_invite_menu_item_new (FolksIndividual *individual,
1083 EmpathyContact *contact)
1085 GtkWidget *item;
1086 GtkWidget *image;
1087 GtkWidget *room_item;
1088 EmpathyChatroomManager *mgr;
1089 GList *rooms = NULL;
1090 GList *names = NULL;
1091 GList *l;
1092 GtkWidget *submenu = NULL;
1093 /* map of chat room names to their objects; just a utility to remove
1094 * duplicates and to make construction of the alphabetized list easier */
1095 GHashTable *name_room_map;
1097 g_return_val_if_fail (FOLKS_IS_INDIVIDUAL (individual) ||
1098 EMPATHY_IS_CONTACT (contact),
1099 NULL);
1101 name_room_map = g_hash_table_new_full (g_str_hash, g_str_equal, NULL,
1102 g_object_unref);
1104 item = gtk_image_menu_item_new_with_mnemonic (_("_Invite to Chat Room"));
1105 image = gtk_image_new_from_icon_name (EMPATHY_IMAGE_GROUP_MESSAGE,
1106 GTK_ICON_SIZE_MENU);
1107 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
1109 mgr = empathy_chatroom_manager_dup_singleton (NULL);
1111 if (contact != NULL)
1113 rooms = empathy_chatroom_manager_get_chatrooms (mgr,
1114 empathy_contact_get_account (contact));
1116 else
1118 GeeSet *personas;
1119 GeeIterator *iter;
1121 /* find the first of this Individual's contacts who can join this room */
1122 personas = folks_individual_get_personas (individual);
1123 iter = gee_iterable_iterator (GEE_ITERABLE (personas));
1124 while (gee_iterator_next (iter))
1126 TpfPersona *persona = gee_iterator_get (iter);
1127 GList *rooms_cur;
1128 TpContact *tp_contact;
1129 EmpathyContact *contact_cur;
1131 if (empathy_folks_persona_is_interesting (FOLKS_PERSONA (persona)))
1133 tp_contact = tpf_persona_get_contact (persona);
1134 contact_cur = empathy_contact_dup_from_tp_contact (tp_contact);
1136 rooms_cur = empathy_chatroom_manager_get_chatrooms (mgr,
1137 empathy_contact_get_account (contact_cur));
1138 rooms = g_list_concat (rooms, rooms_cur);
1140 g_object_unref (contact_cur);
1142 g_clear_object (&persona);
1144 g_clear_object (&iter);
1147 /* alphabetize the rooms */
1148 for (l = rooms; l != NULL; l = g_list_next (l))
1150 EmpathyChatroom *chatroom = l->data;
1151 gboolean existed;
1153 if (empathy_chatroom_get_tp_chat (chatroom) != NULL)
1155 const gchar *name;
1157 name = empathy_chatroom_get_name (chatroom);
1158 existed = (g_hash_table_lookup (name_room_map, name) != NULL);
1159 g_hash_table_insert (name_room_map, (gpointer) name,
1160 g_object_ref (chatroom));
1162 /* this will take care of duplicates in rooms */
1163 if (!existed)
1165 names = g_list_insert_sorted (names, (gpointer) name,
1166 (GCompareFunc) g_strcmp0);
1171 for (l = names; l != NULL; l = g_list_next (l))
1173 const gchar *name = l->data;
1174 EmpathyChatroom *chatroom;
1176 if (G_UNLIKELY (submenu == NULL))
1177 submenu = gtk_menu_new ();
1179 chatroom = g_hash_table_lookup (name_room_map, name);
1180 room_item = create_room_sub_menu (individual, contact, chatroom);
1181 gtk_menu_shell_append ((GtkMenuShell *) submenu, room_item);
1182 gtk_widget_show (room_item);
1185 if (submenu)
1186 gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), submenu);
1187 else
1188 gtk_widget_set_sensitive (item, FALSE);
1190 gtk_widget_show (image);
1192 g_hash_table_destroy (name_room_map);
1193 g_object_unref (mgr);
1194 g_list_free (names);
1195 g_list_free (rooms);
1197 return item;