1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
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>
27 #include <glib/gi18n-lib.h>
29 #include <telepathy-glib/util.h>
31 #include <folks/folks.h>
32 #include <folks/folks-telepathy.h>
34 #include <libempathy/empathy-camera-monitor.h>
35 #include <libempathy/empathy-request-util.h>
36 #include <libempathy/empathy-individual-manager.h>
37 #include <libempathy/empathy-chatroom-manager.h>
38 #include <libempathy/empathy-utils.h>
40 #include "empathy-individual-menu.h"
41 #include "empathy-images.h"
42 #include "empathy-log-window.h"
43 #include "empathy-contact-dialogs.h"
44 #include "empathy-gtk-enum-types.h"
45 #include "empathy-individual-edit-dialog.h"
46 #include "empathy-individual-information-dialog.h"
47 #include "empathy-ui-utils.h"
48 #include "empathy-share-my-desktop.h"
49 #include "empathy-linking-dialog.h"
50 #include "empathy-call-utils.h"
52 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyIndividualMenu)
55 FolksIndividual *individual; /* owned */
56 EmpathyIndividualFeatureFlags features;
57 } EmpathyIndividualMenuPriv;
65 SIGNAL_LINK_CONTACTS_ACTIVATED,
69 static guint signals[LAST_SIGNAL];
71 G_DEFINE_TYPE (EmpathyIndividualMenu, empathy_individual_menu, GTK_TYPE_MENU);
74 individual_menu_add_personas (GtkMenuShell *menu,
75 FolksIndividual *individual,
76 EmpathyIndividualFeatureFlags features)
81 guint persona_count = 0;
84 g_return_if_fail (GTK_IS_MENU (menu));
85 g_return_if_fail (FOLKS_IS_INDIVIDUAL (individual));
86 g_return_if_fail (empathy_folks_individual_contains_contact (individual));
88 personas = folks_individual_get_personas (individual);
89 /* we'll re-use this iterator throughout */
90 iter = gee_iterable_iterator (GEE_ITERABLE (personas));
92 /* Make sure we've got enough valid entries for these menu items to add
94 while (gee_iterator_next (iter))
96 FolksPersona *persona = gee_iterator_get (iter);
97 if (empathy_folks_persona_is_interesting (persona))
100 g_clear_object (&persona);
103 /* return early if these entries would add nothing beyond the "quick" items */
104 if (persona_count <= 1)
107 /* add a separator before the list of personas */
108 item = gtk_separator_menu_item_new ();
109 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
110 gtk_widget_show (item);
112 personas = folks_individual_get_personas (individual);
113 for (c = gee_iterator_first (iter); c; c = gee_iterator_next (iter))
116 GtkWidget *contact_item;
117 GtkWidget *contact_submenu;
118 TpContact *tp_contact;
119 EmpathyContact *contact;
120 TpfPersona *persona = gee_iterator_get (iter);
122 FolksPersonaStore *store;
123 const gchar *account;
126 if (!empathy_folks_persona_is_interesting (FOLKS_PERSONA (persona)))
129 tp_contact = tpf_persona_get_contact (persona);
130 contact = empathy_contact_dup_from_tp_contact (tp_contact);
132 store = folks_persona_get_store (FOLKS_PERSONA (persona));
133 account = folks_persona_store_get_display_name (store);
135 /* Translators: this is used in the context menu for a contact. The first
136 * parameter is a contact ID (e.g. foo@jabber.org) and the second is one
137 * of the user's account IDs (e.g. me@hotmail.com). */
138 label = g_strdup_printf (_("%s (%s)"),
139 folks_persona_get_display_id (FOLKS_PERSONA (persona)), account);
141 contact_item = gtk_image_menu_item_new_with_label (label);
142 gtk_image_menu_item_set_always_show_image (GTK_IMAGE_MENU_ITEM (contact_item),
144 contact_submenu = gtk_menu_new ();
145 gtk_menu_item_set_submenu (GTK_MENU_ITEM (contact_item), contact_submenu);
146 image = gtk_image_new_from_icon_name (
147 empathy_icon_name_for_contact (contact), GTK_ICON_SIZE_MENU);
148 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (contact_item), image);
149 gtk_widget_show (image);
152 if (features & EMPATHY_INDIVIDUAL_FEATURE_CHAT)
154 action = empathy_individual_chat_menu_item_new (NULL, contact);
155 gtk_menu_shell_append (GTK_MENU_SHELL (contact_submenu), action);
156 gtk_widget_show (action);
160 if (features & EMPATHY_INDIVIDUAL_FEATURE_SMS)
162 action = empathy_individual_sms_menu_item_new (NULL, contact);
163 gtk_menu_shell_append (GTK_MENU_SHELL (contact_submenu), action);
164 gtk_widget_show (action);
167 if (features & EMPATHY_INDIVIDUAL_FEATURE_CALL)
170 action = empathy_individual_audio_call_menu_item_new (NULL, contact);
171 gtk_menu_shell_append (GTK_MENU_SHELL (contact_submenu), action);
172 gtk_widget_show (action);
175 action = empathy_individual_video_call_menu_item_new (NULL, contact);
176 gtk_menu_shell_append (GTK_MENU_SHELL (contact_submenu), action);
177 gtk_widget_show (action);
181 if (features & EMPATHY_INDIVIDUAL_FEATURE_LOG)
183 action = empathy_individual_log_menu_item_new (NULL, contact);
184 gtk_menu_shell_append (GTK_MENU_SHELL (contact_submenu), action);
185 gtk_widget_show (action);
189 action = empathy_individual_invite_menu_item_new (NULL, contact);
190 gtk_menu_shell_append (GTK_MENU_SHELL (contact_submenu), action);
191 gtk_widget_show (action);
194 action = empathy_individual_file_transfer_menu_item_new (NULL, contact);
195 gtk_menu_shell_append (GTK_MENU_SHELL (contact_submenu), action);
196 gtk_widget_show (action);
198 /* Share my desktop */
199 action = empathy_individual_share_my_desktop_menu_item_new (NULL,
201 gtk_menu_shell_append (GTK_MENU_SHELL (contact_submenu), action);
202 gtk_widget_show (action);
204 gtk_menu_shell_append (GTK_MENU_SHELL (menu), contact_item);
205 gtk_widget_show (contact_item);
208 g_object_unref (contact);
211 g_clear_object (&persona);
214 g_clear_object (&iter);
218 individual_link_menu_item_activate_cb (EmpathyIndividualMenu *self)
220 EmpathyIndividualMenuPriv *priv = GET_PRIV (self);
223 dialog = empathy_linking_dialog_show (priv->individual, NULL);
224 g_signal_emit (self, signals[SIGNAL_LINK_CONTACTS_ACTIVATED], 0, dialog);
228 empathy_individual_menu_init (EmpathyIndividualMenu *self)
230 EmpathyIndividualMenuPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
231 EMPATHY_TYPE_INDIVIDUAL_MENU, EmpathyIndividualMenuPriv);
237 constructed (GObject *object)
239 EmpathyIndividualMenuPriv *priv = GET_PRIV (object);
242 FolksIndividual *individual;
243 EmpathyIndividualFeatureFlags features;
246 shell = GTK_MENU_SHELL (object);
247 individual = priv->individual;
248 features = priv->features;
251 if (features & EMPATHY_INDIVIDUAL_FEATURE_CHAT)
253 item = empathy_individual_chat_menu_item_new (individual, NULL);
256 gtk_menu_shell_append (shell, item);
257 gtk_widget_show (item);
262 if (features & EMPATHY_INDIVIDUAL_FEATURE_SMS)
264 item = empathy_individual_sms_menu_item_new (individual, NULL);
267 gtk_menu_shell_append (shell, item);
268 gtk_widget_show (item);
272 if (features & EMPATHY_INDIVIDUAL_FEATURE_CALL)
275 item = empathy_individual_audio_call_menu_item_new (individual, NULL);
276 gtk_menu_shell_append (shell, item);
277 gtk_widget_show (item);
280 item = empathy_individual_video_call_menu_item_new (individual, NULL);
281 gtk_menu_shell_append (shell, item);
282 gtk_widget_show (item);
286 if (features & EMPATHY_INDIVIDUAL_FEATURE_LOG)
288 item = empathy_individual_log_menu_item_new (individual, NULL);
289 gtk_menu_shell_append (shell, item);
290 gtk_widget_show (item);
294 item = empathy_individual_invite_menu_item_new (individual, NULL);
295 gtk_menu_shell_append (shell, item);
296 gtk_widget_show (item);
299 item = empathy_individual_file_transfer_menu_item_new (individual, NULL);
300 gtk_menu_shell_append (shell, item);
301 gtk_widget_show (item);
303 /* Share my desktop */
304 /* FIXME we should add the "Share my desktop" menu item if Vino is
305 a registered handler in MC5 */
306 item = empathy_individual_share_my_desktop_menu_item_new (individual, NULL);
307 gtk_menu_shell_append (shell, item);
308 gtk_widget_show (item);
310 /* Menu items to target specific contacts */
311 individual_menu_add_personas (GTK_MENU_SHELL (object), individual, features);
314 if (features & (EMPATHY_INDIVIDUAL_FEATURE_EDIT |
315 EMPATHY_INDIVIDUAL_FEATURE_INFO |
316 EMPATHY_INDIVIDUAL_FEATURE_FAVOURITE |
317 EMPATHY_INDIVIDUAL_FEATURE_LINK))
319 item = gtk_separator_menu_item_new ();
320 gtk_menu_shell_append (shell, item);
321 gtk_widget_show (item);
325 if (features & EMPATHY_INDIVIDUAL_FEATURE_EDIT)
327 item = empathy_individual_edit_menu_item_new (individual);
328 gtk_menu_shell_append (shell, item);
329 gtk_widget_show (item);
333 if (features & EMPATHY_INDIVIDUAL_FEATURE_LINK)
335 item = empathy_individual_link_menu_item_new (individual);
336 gtk_menu_shell_append (shell, item);
338 g_signal_connect_swapped (item, "activate",
339 (GCallback) individual_link_menu_item_activate_cb, object);
341 gtk_widget_show (item);
345 if (features & EMPATHY_INDIVIDUAL_FEATURE_INFO)
347 item = empathy_individual_info_menu_item_new (individual);
348 gtk_menu_shell_append (shell, item);
349 gtk_widget_show (item);
352 /* Favorite checkbox */
353 if (features & EMPATHY_INDIVIDUAL_FEATURE_FAVOURITE)
355 item = empathy_individual_favourite_menu_item_new (individual);
356 gtk_menu_shell_append (shell, item);
357 gtk_widget_show (item);
362 get_property (GObject *object,
367 EmpathyIndividualMenuPriv *priv;
369 priv = GET_PRIV (object);
373 case PROP_INDIVIDUAL:
374 g_value_set_object (value, priv->individual);
377 g_value_set_flags (value, priv->features);
380 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
386 set_property (GObject *object,
391 EmpathyIndividualMenuPriv *priv;
393 priv = GET_PRIV (object);
397 case PROP_INDIVIDUAL:
398 priv->individual = g_value_dup_object (value);
401 priv->features = g_value_get_flags (value);
404 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
410 dispose (GObject *object)
412 EmpathyIndividualMenuPriv *priv = GET_PRIV (object);
414 tp_clear_object (&priv->individual);
416 G_OBJECT_CLASS (empathy_individual_menu_parent_class)->dispose (object);
420 empathy_individual_menu_class_init (EmpathyIndividualMenuClass *klass)
422 GObjectClass *object_class = G_OBJECT_CLASS (klass);
424 object_class->constructed = constructed;
425 object_class->get_property = get_property;
426 object_class->set_property = set_property;
427 object_class->dispose = dispose;
430 * EmpathyIndividualMenu:individual:
432 * The #FolksIndividual the menu is for.
434 g_object_class_install_property (object_class, PROP_INDIVIDUAL,
435 g_param_spec_object ("individual",
437 "The #FolksIndividual the menu is for.",
438 FOLKS_TYPE_INDIVIDUAL,
439 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
442 * EmpathyIndividualMenu:features:
444 * A set of feature flags controlling which entries are shown.
446 g_object_class_install_property (object_class, PROP_FEATURES,
447 g_param_spec_flags ("features",
449 "A set of feature flags controlling which entries are shown.",
450 EMPATHY_TYPE_INDIVIDUAL_FEATURE_FLAGS,
451 EMPATHY_INDIVIDUAL_FEATURE_NONE,
452 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
454 signals[SIGNAL_LINK_CONTACTS_ACTIVATED] =
455 g_signal_new ("link-contacts-activated", G_OBJECT_CLASS_TYPE (klass),
456 G_SIGNAL_RUN_LAST, 0, NULL, NULL,
457 g_cclosure_marshal_VOID__OBJECT,
458 G_TYPE_NONE, 1, EMPATHY_TYPE_LINKING_DIALOG);
460 g_type_class_add_private (object_class, sizeof (EmpathyIndividualMenuPriv));
464 empathy_individual_menu_new (FolksIndividual *individual,
465 EmpathyIndividualFeatureFlags features)
467 g_return_val_if_fail (FOLKS_IS_INDIVIDUAL (individual), NULL);
468 g_return_val_if_fail (features != EMPATHY_INDIVIDUAL_FEATURE_NONE, NULL);
470 return g_object_new (EMPATHY_TYPE_INDIVIDUAL_MENU,
471 "individual", individual,
472 "features", features,
476 /* Like menu_item_set_first_contact(), but always operates upon the given
477 * contact. If the contact is non-NULL, it is assumed that the menu entry should
480 menu_item_set_contact (GtkWidget *item,
481 EmpathyContact *contact,
482 GCallback activate_callback,
483 EmpathyActionType action_type)
485 gboolean can_do_action = FALSE;
488 can_do_action = empathy_contact_can_do_action (contact, action_type);
489 gtk_widget_set_sensitive (item, can_do_action);
491 if (can_do_action == TRUE)
493 /* We want to make sure that the EmpathyContact stays alive while the
494 * signal is connected. */
495 g_signal_connect_data (item, "activate", G_CALLBACK (activate_callback),
496 g_object_ref (contact), (GClosureNotify) g_object_unref, 0);
499 return can_do_action;
503 * Set the given menu @item to call @activate_callback using the TpContact
504 * (associated with @individual) with the highest availability who is also valid
505 * whenever @item is activated.
507 * @action_type is the type of action performed by the menu entry; this is used
508 * so that only contacts which can perform that action (e.g. are capable of
509 * receiving video calls) are selected, as appropriate.
512 menu_item_set_first_contact (GtkWidget *item,
513 FolksIndividual *individual,
514 GCallback activate_callback,
515 EmpathyActionType action_type)
517 EmpathyContact *best_contact;
519 best_contact = empathy_contact_dup_best_for_action (individual, action_type);
520 menu_item_set_contact (item, best_contact, G_CALLBACK (activate_callback),
522 tp_clear_object (&best_contact);
528 empathy_individual_chat_menu_item_activated (GtkMenuItem *item,
529 EmpathyContact *contact)
531 g_return_if_fail (EMPATHY_IS_CONTACT (contact));
533 empathy_chat_with_contact (contact, empathy_get_current_action_time ());
537 empathy_individual_chat_menu_item_new (FolksIndividual *individual,
538 EmpathyContact *contact)
543 g_return_val_if_fail ((FOLKS_IS_INDIVIDUAL (individual) &&
544 empathy_folks_individual_contains_contact (individual)) ||
545 EMPATHY_IS_CONTACT (contact),
548 item = gtk_image_menu_item_new_with_mnemonic (_("_Chat"));
549 image = gtk_image_new_from_icon_name (EMPATHY_IMAGE_MESSAGE,
551 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
552 gtk_widget_show (image);
556 menu_item_set_contact (item, contact,
557 G_CALLBACK (empathy_individual_chat_menu_item_activated),
558 EMPATHY_ACTION_CHAT);
562 menu_item_set_first_contact (item, individual,
563 G_CALLBACK (empathy_individual_chat_menu_item_activated),
564 EMPATHY_ACTION_CHAT);
571 empathy_individual_sms_menu_item_activated (GtkMenuItem *item,
572 EmpathyContact *contact)
574 g_return_if_fail (EMPATHY_IS_CONTACT (contact));
576 empathy_sms_contact_id (
577 empathy_contact_get_account (contact),
578 empathy_contact_get_id (contact),
579 empathy_get_current_action_time ());
583 empathy_individual_sms_menu_item_new (FolksIndividual *individual,
584 EmpathyContact *contact)
589 g_return_val_if_fail ((FOLKS_IS_INDIVIDUAL (individual) &&
590 empathy_folks_individual_contains_contact (individual)) ||
591 EMPATHY_IS_CONTACT (contact),
594 item = gtk_image_menu_item_new_with_mnemonic (_("_SMS"));
595 image = gtk_image_new_from_icon_name (EMPATHY_IMAGE_SMS,
597 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
598 gtk_widget_show (image);
602 menu_item_set_contact (item, contact,
603 G_CALLBACK (empathy_individual_sms_menu_item_activated),
608 menu_item_set_first_contact (item, individual,
609 G_CALLBACK (empathy_individual_sms_menu_item_activated),
617 empathy_individual_audio_call_menu_item_activated (GtkMenuItem *item,
618 EmpathyContact *contact)
620 g_return_if_fail (EMPATHY_IS_CONTACT (contact));
622 empathy_call_new_with_streams (empathy_contact_get_id (contact),
623 empathy_contact_get_account (contact),
625 empathy_get_current_action_time ());
629 empathy_individual_audio_call_menu_item_new (FolksIndividual *individual,
630 EmpathyContact *contact)
635 g_return_val_if_fail (FOLKS_IS_INDIVIDUAL (individual) ||
636 EMPATHY_IS_CONTACT (contact),
639 item = gtk_image_menu_item_new_with_mnemonic (C_("menu item", "_Audio Call"));
640 image = gtk_image_new_from_icon_name (EMPATHY_IMAGE_VOIP, GTK_ICON_SIZE_MENU);
641 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
642 gtk_widget_show (image);
646 menu_item_set_contact (item, contact,
647 G_CALLBACK (empathy_individual_audio_call_menu_item_activated),
648 EMPATHY_ACTION_AUDIO_CALL);
652 menu_item_set_first_contact (item, individual,
653 G_CALLBACK (empathy_individual_audio_call_menu_item_activated),
654 EMPATHY_ACTION_AUDIO_CALL);
661 empathy_individual_video_call_menu_item_activated (GtkMenuItem *item,
662 EmpathyContact *contact)
664 g_return_if_fail (EMPATHY_IS_CONTACT (contact));
666 empathy_call_new_with_streams (empathy_contact_get_id (contact),
667 empathy_contact_get_account (contact),
669 empathy_get_current_action_time ());
673 empathy_individual_video_call_menu_item_new (FolksIndividual *individual,
674 EmpathyContact *contact)
678 EmpathyCameraMonitor *monitor;
680 g_return_val_if_fail (FOLKS_IS_INDIVIDUAL (individual) ||
681 EMPATHY_IS_CONTACT (contact),
684 item = gtk_image_menu_item_new_with_mnemonic (C_("menu item", "_Video Call"));
685 image = gtk_image_new_from_icon_name (EMPATHY_IMAGE_VIDEO_CALL,
687 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
688 gtk_widget_show (image);
692 menu_item_set_contact (item, contact,
693 G_CALLBACK (empathy_individual_video_call_menu_item_activated),
694 EMPATHY_ACTION_VIDEO_CALL);
698 menu_item_set_first_contact (item, individual,
699 G_CALLBACK (empathy_individual_video_call_menu_item_activated),
700 EMPATHY_ACTION_VIDEO_CALL);
703 /* Only follow available cameras if the contact can do Video calls */
704 if (gtk_widget_get_sensitive (item))
706 monitor = empathy_camera_monitor_dup_singleton ();
707 g_object_set_data_full (G_OBJECT (item),
708 "monitor", monitor, g_object_unref);
709 g_object_bind_property (monitor, "available", item, "sensitive",
710 G_BINDING_SYNC_CREATE);
717 empathy_individual_log_menu_item_activated (GtkMenuItem *item,
718 EmpathyContact *contact)
720 g_return_if_fail (EMPATHY_IS_CONTACT (contact));
722 empathy_log_window_show (empathy_contact_get_account (contact),
723 empathy_contact_get_id (contact), FALSE, NULL);
727 empathy_individual_log_menu_item_new (FolksIndividual *individual,
728 EmpathyContact *contact)
733 g_return_val_if_fail (FOLKS_IS_INDIVIDUAL (individual) ||
734 EMPATHY_IS_CONTACT (contact),
737 item = gtk_image_menu_item_new_with_mnemonic (_("_Previous Conversations"));
738 image = gtk_image_new_from_icon_name (EMPATHY_IMAGE_LOG, GTK_ICON_SIZE_MENU);
739 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
740 gtk_widget_show (image);
744 menu_item_set_contact (item, contact,
745 G_CALLBACK (empathy_individual_log_menu_item_activated),
746 EMPATHY_ACTION_VIEW_LOGS);
750 menu_item_set_first_contact (item, individual,
751 G_CALLBACK (empathy_individual_log_menu_item_activated),
752 EMPATHY_ACTION_VIEW_LOGS);
759 empathy_individual_file_transfer_menu_item_activated (GtkMenuItem *item,
760 EmpathyContact *contact)
762 g_return_if_fail (EMPATHY_IS_CONTACT (contact));
764 empathy_send_file_with_file_chooser (contact);
768 empathy_individual_file_transfer_menu_item_new (FolksIndividual *individual,
769 EmpathyContact *contact)
774 g_return_val_if_fail (FOLKS_IS_INDIVIDUAL (individual) ||
775 EMPATHY_IS_CONTACT (contact),
778 item = gtk_image_menu_item_new_with_mnemonic (_("Send File"));
779 image = gtk_image_new_from_icon_name (EMPATHY_IMAGE_DOCUMENT_SEND,
781 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
782 gtk_widget_show (image);
786 menu_item_set_contact (item, contact,
787 G_CALLBACK (empathy_individual_file_transfer_menu_item_activated),
788 EMPATHY_ACTION_SEND_FILE);
792 menu_item_set_first_contact (item, individual,
793 G_CALLBACK (empathy_individual_file_transfer_menu_item_activated),
794 EMPATHY_ACTION_SEND_FILE);
801 empathy_individual_share_my_desktop_menu_item_activated (GtkMenuItem *item,
802 EmpathyContact *contact)
804 g_return_if_fail (EMPATHY_IS_CONTACT (contact));
806 empathy_share_my_desktop_share_with_contact (contact);
810 empathy_individual_share_my_desktop_menu_item_new (FolksIndividual *individual,
811 EmpathyContact *contact)
816 g_return_val_if_fail (FOLKS_IS_INDIVIDUAL (individual) ||
817 EMPATHY_IS_CONTACT (contact),
820 item = gtk_image_menu_item_new_with_mnemonic (_("Share My Desktop"));
821 image = gtk_image_new_from_icon_name (GTK_STOCK_NETWORK, GTK_ICON_SIZE_MENU);
822 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
823 gtk_widget_show (image);
827 menu_item_set_contact (item, contact,
828 G_CALLBACK (empathy_individual_share_my_desktop_menu_item_activated),
829 EMPATHY_ACTION_SHARE_MY_DESKTOP);
833 menu_item_set_first_contact (item, individual,
834 G_CALLBACK (empathy_individual_share_my_desktop_menu_item_activated),
835 EMPATHY_ACTION_SHARE_MY_DESKTOP);
842 favourite_menu_item_toggled_cb (GtkCheckMenuItem *item,
843 FolksIndividual *individual)
845 folks_favourite_details_set_is_favourite (
846 FOLKS_FAVOURITE_DETAILS (individual),
847 gtk_check_menu_item_get_active (item));
851 empathy_individual_favourite_menu_item_new (FolksIndividual *individual)
855 item = gtk_check_menu_item_new_with_label (_("Favorite"));
857 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item),
858 folks_favourite_details_get_is_favourite (
859 FOLKS_FAVOURITE_DETAILS (individual)));
861 g_signal_connect (item, "toggled",
862 G_CALLBACK (favourite_menu_item_toggled_cb), individual);
868 individual_info_menu_item_activate_cb (FolksIndividual *individual)
870 empathy_individual_information_dialog_show (individual, NULL);
874 empathy_individual_info_menu_item_new (FolksIndividual *individual)
879 g_return_val_if_fail (FOLKS_IS_INDIVIDUAL (individual), NULL);
880 g_return_val_if_fail (empathy_folks_individual_contains_contact (individual),
883 item = gtk_image_menu_item_new_with_mnemonic (_("Infor_mation"));
884 image = gtk_image_new_from_icon_name (EMPATHY_IMAGE_CONTACT_INFORMATION,
886 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
887 gtk_widget_show (image);
889 g_signal_connect_swapped (item, "activate",
890 G_CALLBACK (individual_info_menu_item_activate_cb),
897 individual_edit_menu_item_activate_cb (FolksIndividual *individual)
899 empathy_individual_edit_dialog_show (individual, NULL);
903 empathy_individual_edit_menu_item_new (FolksIndividual *individual)
905 EmpathyIndividualManager *manager;
908 gboolean enable = FALSE;
909 EmpathyContact *contact;
911 g_return_val_if_fail (FOLKS_IS_INDIVIDUAL (individual), NULL);
913 contact = empathy_contact_dup_from_folks_individual (individual);
915 g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL);
917 if (empathy_individual_manager_initialized ())
919 TpConnection *connection;
921 manager = empathy_individual_manager_dup_singleton ();
922 connection = empathy_contact_get_connection (contact);
924 enable = (empathy_connection_can_alias_personas (connection) &&
925 empathy_connection_can_group_personas (connection));
927 g_object_unref (manager);
930 item = gtk_image_menu_item_new_with_mnemonic (
931 C_("Edit individual (contextual menu)", "_Edit"));
932 image = gtk_image_new_from_icon_name (GTK_STOCK_EDIT, GTK_ICON_SIZE_MENU);
933 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
934 gtk_widget_show (image);
936 gtk_widget_set_sensitive (item, enable);
938 g_signal_connect_swapped (item, "activate",
939 G_CALLBACK (individual_edit_menu_item_activate_cb), individual);
941 g_object_unref (contact);
947 empathy_individual_link_menu_item_new (FolksIndividual *individual)
950 /*GtkWidget *image;*/
952 g_return_val_if_fail (FOLKS_IS_INDIVIDUAL (individual), NULL);
954 item = gtk_image_menu_item_new_with_mnemonic (
955 /* Translators: this is a verb meaning "to connect two contacts together
956 * to form a meta-contact". */
957 C_("Link individual (contextual menu)", "_Link Contacts…"));
959 /*image = gtk_image_new_from_icon_name (GTK_STOCK_EDIT, GTK_ICON_SIZE_MENU);
960 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
961 gtk_widget_show (image);*/
963 /* Only allow trusted Individuals to be linked */
964 gtk_widget_set_sensitive (item,
965 folks_individual_get_trust_level (individual) ==
966 FOLKS_TRUST_LEVEL_PERSONAS);
973 FolksIndividual *individual;
974 EmpathyContact *contact;
975 EmpathyChatroom *chatroom;
978 static RoomSubMenuData *
979 room_sub_menu_data_new (FolksIndividual *individual,
980 EmpathyContact *contact,
981 EmpathyChatroom *chatroom)
983 RoomSubMenuData *data;
985 data = g_slice_new0 (RoomSubMenuData);
986 if (individual != NULL)
987 data->individual = g_object_ref (individual);
989 data->contact = g_object_ref (contact);
990 data->chatroom = g_object_ref (chatroom);
996 room_sub_menu_data_free (RoomSubMenuData *data)
998 tp_clear_object (&data->individual);
999 tp_clear_object (&data->contact);
1000 g_object_unref (data->chatroom);
1001 g_slice_free (RoomSubMenuData, data);
1005 room_sub_menu_activate_cb (GtkWidget *item,
1006 RoomSubMenuData *data)
1008 EmpathyTpChat *chat;
1009 EmpathyChatroomManager *mgr;
1010 EmpathyContact *contact = NULL;
1012 chat = empathy_chatroom_get_tp_chat (data->chatroom);
1015 /* channel was invalidated. Ignoring */
1019 mgr = empathy_chatroom_manager_dup_singleton (NULL);
1021 if (data->contact != NULL)
1022 contact = g_object_ref (data->contact);
1028 /* find the first of this Individual's contacts who can join this room */
1029 personas = folks_individual_get_personas (data->individual);
1031 iter = gee_iterable_iterator (GEE_ITERABLE (personas));
1032 while (gee_iterator_next (iter) && (contact == NULL))
1034 TpfPersona *persona = gee_iterator_get (iter);
1035 TpContact *tp_contact;
1038 if (empathy_folks_persona_is_interesting (FOLKS_PERSONA (persona)))
1040 tp_contact = tpf_persona_get_contact (persona);
1041 contact = empathy_contact_dup_from_tp_contact (tp_contact);
1043 rooms = empathy_chatroom_manager_get_chatrooms (mgr,
1044 empathy_contact_get_account (contact));
1046 if (g_list_find (rooms, data->chatroom) == NULL)
1047 g_clear_object (&contact);
1049 /* if contact != NULL here, we've found our match */
1051 g_list_free (rooms);
1053 g_clear_object (&persona);
1055 g_clear_object (&iter);
1058 g_object_unref (mgr);
1060 if (contact == NULL)
1062 /* contact disappeared. Ignoring */
1066 g_return_if_fail (EMPATHY_IS_CONTACT (contact));
1068 /* send invitation */
1069 empathy_contact_list_add (EMPATHY_CONTACT_LIST (chat),
1070 contact, _("Inviting you to this room"));
1073 g_object_unref (contact);
1077 create_room_sub_menu (FolksIndividual *individual,
1078 EmpathyContact *contact,
1079 EmpathyChatroom *chatroom)
1082 RoomSubMenuData *data;
1084 item = gtk_menu_item_new_with_label (empathy_chatroom_get_name (chatroom));
1085 data = room_sub_menu_data_new (individual, contact, chatroom);
1086 g_signal_connect_data (item, "activate",
1087 G_CALLBACK (room_sub_menu_activate_cb), data,
1088 (GClosureNotify) room_sub_menu_data_free, 0);
1094 empathy_individual_invite_menu_item_new (FolksIndividual *individual,
1095 EmpathyContact *contact)
1099 GtkWidget *room_item;
1100 EmpathyChatroomManager *mgr;
1101 GList *rooms = NULL;
1102 GList *names = NULL;
1104 GtkWidget *submenu = NULL;
1105 /* map of chat room names to their objects; just a utility to remove
1106 * duplicates and to make construction of the alphabetized list easier */
1107 GHashTable *name_room_map;
1109 g_return_val_if_fail (FOLKS_IS_INDIVIDUAL (individual) ||
1110 EMPATHY_IS_CONTACT (contact),
1113 name_room_map = g_hash_table_new_full (g_str_hash, g_str_equal, NULL,
1116 item = gtk_image_menu_item_new_with_mnemonic (_("_Invite to Chat Room"));
1117 image = gtk_image_new_from_icon_name (EMPATHY_IMAGE_GROUP_MESSAGE,
1118 GTK_ICON_SIZE_MENU);
1119 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
1121 mgr = empathy_chatroom_manager_dup_singleton (NULL);
1123 if (contact != NULL)
1125 rooms = empathy_chatroom_manager_get_chatrooms (mgr,
1126 empathy_contact_get_account (contact));
1133 /* find the first of this Individual's contacts who can join this room */
1134 personas = folks_individual_get_personas (individual);
1135 iter = gee_iterable_iterator (GEE_ITERABLE (personas));
1136 while (gee_iterator_next (iter))
1138 TpfPersona *persona = gee_iterator_get (iter);
1140 TpContact *tp_contact;
1141 EmpathyContact *contact_cur;
1143 if (empathy_folks_persona_is_interesting (FOLKS_PERSONA (persona)))
1145 tp_contact = tpf_persona_get_contact (persona);
1146 contact_cur = empathy_contact_dup_from_tp_contact (tp_contact);
1148 rooms_cur = empathy_chatroom_manager_get_chatrooms (mgr,
1149 empathy_contact_get_account (contact_cur));
1150 rooms = g_list_concat (rooms, rooms_cur);
1152 g_object_unref (contact_cur);
1154 g_clear_object (&persona);
1156 g_clear_object (&iter);
1159 /* alphabetize the rooms */
1160 for (l = rooms; l != NULL; l = g_list_next (l))
1162 EmpathyChatroom *chatroom = l->data;
1165 if (empathy_chatroom_get_tp_chat (chatroom) != NULL)
1169 name = empathy_chatroom_get_name (chatroom);
1170 existed = (g_hash_table_lookup (name_room_map, name) != NULL);
1171 g_hash_table_insert (name_room_map, (gpointer) name,
1172 g_object_ref (chatroom));
1174 /* this will take care of duplicates in rooms */
1177 names = g_list_insert_sorted (names, (gpointer) name,
1178 (GCompareFunc) g_strcmp0);
1183 for (l = names; l != NULL; l = g_list_next (l))
1185 const gchar *name = l->data;
1186 EmpathyChatroom *chatroom;
1188 if (G_UNLIKELY (submenu == NULL))
1189 submenu = gtk_menu_new ();
1191 chatroom = g_hash_table_lookup (name_room_map, name);
1192 room_item = create_room_sub_menu (individual, contact, chatroom);
1193 gtk_menu_shell_append ((GtkMenuShell *) submenu, room_item);
1194 gtk_widget_show (room_item);
1198 gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), submenu);
1200 gtk_widget_set_sensitive (item, FALSE);
1202 gtk_widget_show (image);
1204 g_hash_table_destroy (name_room_map);
1205 g_object_unref (mgr);
1206 g_list_free (names);
1207 g_list_free (rooms);