]> git.0d.be Git - empathy.git/blob - libempathy-gtk/empathy-contact-menu.c
Force windows to jump to the foreground if we present them
[empathy.git] / libempathy-gtk / empathy-contact-menu.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * Copyright (C) 2008 Collabora Ltd.
4  *
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.
9  *
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.
14  *
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
18  *
19  * Authors: Xavier Claessens <xclaesse@gmail.com>
20  */
21
22 #include "config.h"
23
24 #include <string.h>
25
26 #include <glib/gi18n-lib.h>
27 #include <gtk/gtk.h>
28 #ifdef ENABLE_TPL
29 #include <telepathy-logger/log-manager.h>
30 #else
31
32 #include <libempathy/empathy-log-manager.h>
33 #endif /* ENABLE_TPL */
34 #include <libempathy/empathy-call-factory.h>
35 #include <libempathy/empathy-contact-manager.h>
36 #include <libempathy/empathy-dispatcher.h>
37 #include <libempathy/empathy-utils.h>
38 #include <libempathy/empathy-chatroom-manager.h>
39 #include <libempathy/empathy-contact-manager.h>
40
41 #include "empathy-contact-menu.h"
42 #include "empathy-images.h"
43 #include "empathy-log-window.h"
44 #include "empathy-contact-dialogs.h"
45 #include "empathy-ui-utils.h"
46 #include "empathy-share-my-desktop.h"
47
48 GtkWidget *
49 empathy_contact_menu_new (EmpathyContact             *contact,
50                           EmpathyContactFeatureFlags  features)
51 {
52         GtkWidget    *menu;
53         GtkMenuShell *shell;
54         GtkWidget    *item;
55
56         g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL);
57
58         if (features == EMPATHY_CONTACT_FEATURE_NONE) {
59                 return NULL;
60         }
61
62         menu = gtk_menu_new ();
63         shell = GTK_MENU_SHELL (menu);
64
65         /* Add Contact */
66         item = empathy_contact_add_menu_item_new (contact);
67         if (item) {
68                 gtk_menu_shell_append (shell, item);
69                 gtk_widget_show (item);
70         }
71
72         /* Chat */
73         if (features & EMPATHY_CONTACT_FEATURE_CHAT) {
74                 item = empathy_contact_chat_menu_item_new (contact);
75                 gtk_menu_shell_append (shell, item);
76                 gtk_widget_show (item);
77         }
78
79         if (features & EMPATHY_CONTACT_FEATURE_CALL) {
80                 /* Audio Call */
81                 item = empathy_contact_audio_call_menu_item_new (contact);
82                 gtk_menu_shell_append (shell, item);
83                 gtk_widget_show (item);
84
85                 /* Video Call */
86                 item = empathy_contact_video_call_menu_item_new (contact);
87                 gtk_menu_shell_append (shell, item);
88                 gtk_widget_show (item);
89         }
90
91         /* Log */
92         if (features & EMPATHY_CONTACT_FEATURE_LOG) {
93                 item = empathy_contact_log_menu_item_new (contact);
94                 gtk_menu_shell_append (shell, item);
95                 gtk_widget_show (item);
96         }
97
98         /* Invite */
99         item = empathy_contact_invite_menu_item_new (contact);
100         gtk_menu_shell_append (shell, item);
101         gtk_widget_show (item);
102
103         /* File transfer */
104         item = empathy_contact_file_transfer_menu_item_new (contact);
105         gtk_menu_shell_append (shell, item);
106         gtk_widget_show (item);
107
108         /* Share my desktop */
109         /* FIXME we should add the "Share my desktop" menu item if Vino is
110         a registered handler in MC5 */
111         item = empathy_contact_share_my_desktop_menu_item_new (contact);
112         gtk_menu_shell_append (shell, item);
113         gtk_widget_show (item);
114
115         /* Separator */
116         if (features & (EMPATHY_CONTACT_FEATURE_EDIT |
117                         EMPATHY_CONTACT_FEATURE_INFO)) {
118                 item = gtk_separator_menu_item_new ();
119                 gtk_menu_shell_append (shell, item);
120                 gtk_widget_show (item);
121         }
122
123         /* Edit */
124         if (features & EMPATHY_CONTACT_FEATURE_EDIT) {
125                 item = empathy_contact_edit_menu_item_new (contact);
126                 gtk_menu_shell_append (shell, item);
127                 gtk_widget_show (item);
128         }
129
130         /* Info */
131         if (features & EMPATHY_CONTACT_FEATURE_INFO) {
132                 item = empathy_contact_info_menu_item_new (contact);
133                 gtk_menu_shell_append (shell, item);
134                 gtk_widget_show (item);
135         }
136
137         return menu;
138 }
139
140 static void
141 empathy_contact_add_menu_item_activated (GtkMenuItem *item,
142         EmpathyContact *contact)
143 {
144         GtkWidget *toplevel;
145
146         toplevel = gtk_widget_get_toplevel (GTK_WIDGET (item));
147         if (!gtk_widget_is_toplevel (toplevel) || !GTK_IS_WINDOW (toplevel)) {
148                 toplevel = NULL;
149         }
150
151         empathy_new_contact_dialog_show_with_contact (GTK_WINDOW (toplevel),
152                                                       contact);
153 }
154
155 GtkWidget *
156 empathy_contact_add_menu_item_new (EmpathyContact *contact)
157 {
158         GtkWidget *item;
159         GtkWidget *image;
160         EmpathyContactManager *manager;
161         TpConnection *connection;
162         GList *l, *members;
163         gboolean found = FALSE;
164         EmpathyContactListFlags flags;
165
166         g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL);
167
168         if (!empathy_contact_manager_initialized ()) {
169                 return NULL;
170         }
171
172         manager = empathy_contact_manager_dup_singleton ();
173         connection = empathy_contact_get_connection (contact);
174
175         flags = empathy_contact_manager_get_flags_for_connection (manager,
176                         connection);
177
178         if (!(flags & EMPATHY_CONTACT_LIST_CAN_ADD)) {
179                 return NULL;
180         }
181
182         members = empathy_contact_list_get_members (EMPATHY_CONTACT_LIST (manager));
183         for (l = members; l; l = l->next) {
184                 if (!found && empathy_contact_equal (l->data, contact)) {
185                         found = TRUE;
186                         /* we keep iterating so that we don't leak contact
187                          * refs */
188                 }
189
190                 g_object_unref (l->data);
191         }
192         g_list_free (members);
193         g_object_unref (manager);
194
195         if (found) {
196                 return NULL;
197         }
198
199         item = gtk_image_menu_item_new_with_mnemonic (_("_Add Contact…"));
200         image = gtk_image_new_from_icon_name (GTK_STOCK_ADD,
201                                               GTK_ICON_SIZE_MENU);
202         gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
203
204         g_signal_connect (item, "activate",
205                         G_CALLBACK (empathy_contact_add_menu_item_activated),
206                         contact);
207
208         return item;
209 }
210
211 static void
212 empathy_contact_chat_menu_item_activated (GtkMenuItem *item,
213         EmpathyContact *contact)
214 {
215   empathy_dispatcher_chat_with_contact (contact, NULL, NULL);
216 }
217
218 GtkWidget *
219 empathy_contact_chat_menu_item_new (EmpathyContact *contact)
220 {
221         GtkWidget *item;
222         GtkWidget *image;
223
224         g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL);
225
226         item = gtk_image_menu_item_new_with_mnemonic (_("_Chat"));
227         image = gtk_image_new_from_icon_name (EMPATHY_IMAGE_MESSAGE,
228                                               GTK_ICON_SIZE_MENU);
229         gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
230         gtk_widget_show (image);
231
232         g_signal_connect (item, "activate",
233                                   G_CALLBACK (empathy_contact_chat_menu_item_activated),
234                                   contact);
235
236         return item;
237 }
238
239 static void
240 empathy_contact_audio_call_menu_item_activated (GtkMenuItem *item,
241         EmpathyContact *contact)
242 {
243         EmpathyCallFactory *factory;
244
245         factory = empathy_call_factory_get ();
246         empathy_call_factory_new_call_with_streams (factory, contact, TRUE, FALSE);
247 }
248
249 GtkWidget *
250 empathy_contact_audio_call_menu_item_new (EmpathyContact *contact)
251 {
252         GtkWidget *item;
253         GtkWidget *image;
254
255         g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL);
256
257         item = gtk_image_menu_item_new_with_mnemonic (C_("menu item", "_Audio Call"));
258         image = gtk_image_new_from_icon_name (EMPATHY_IMAGE_VOIP,
259                                               GTK_ICON_SIZE_MENU);
260         gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
261         gtk_widget_set_sensitive (item, empathy_contact_can_voip_audio (contact));
262         gtk_widget_show (image);
263
264         g_signal_connect (item, "activate",
265                                   G_CALLBACK (empathy_contact_audio_call_menu_item_activated),
266                                   contact);
267
268         return item;
269 }
270
271 static void
272 empathy_contact_video_call_menu_item_activated (GtkMenuItem *item,
273         EmpathyContact *contact)
274 {
275         EmpathyCallFactory *factory;
276
277         factory = empathy_call_factory_get ();
278         empathy_call_factory_new_call_with_streams (factory, contact, TRUE, TRUE);
279 }
280
281 GtkWidget *
282 empathy_contact_video_call_menu_item_new (EmpathyContact *contact)
283 {
284         GtkWidget *item;
285         GtkWidget *image;
286
287         g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL);
288
289         item = gtk_image_menu_item_new_with_mnemonic (C_("menu item", "_Video Call"));
290         image = gtk_image_new_from_icon_name (EMPATHY_IMAGE_VIDEO_CALL,
291                                               GTK_ICON_SIZE_MENU);
292         gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
293         gtk_widget_set_sensitive (item, empathy_contact_can_voip_video (contact));
294         gtk_widget_show (image);
295
296         g_signal_connect (item, "activate",
297                                   G_CALLBACK (empathy_contact_video_call_menu_item_activated),
298                                   contact);
299
300         return item;
301 }
302
303 static void
304 contact_log_menu_item_activate_cb (EmpathyContact *contact)
305 {
306         empathy_log_window_show (empathy_contact_get_account (contact),
307                                  empathy_contact_get_id (contact),
308                                  FALSE, NULL);
309 }
310
311 GtkWidget *
312 empathy_contact_log_menu_item_new (EmpathyContact *contact)
313 {
314 #ifndef ENABLE_TPL
315         EmpathyLogManager *manager;
316 #else
317         TplLogManager     *manager;
318 #endif /* ENABLE_TPL */
319         gboolean           have_log;
320         GtkWidget         *item;
321         GtkWidget         *image;
322
323         g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL);
324
325 #ifndef ENABLE_TPL
326         manager = empathy_log_manager_dup_singleton ();
327         have_log = empathy_log_manager_exists (manager,
328                                                empathy_contact_get_account (contact),
329                                                empathy_contact_get_id (contact),
330                                                FALSE);
331 #else
332         manager = tpl_log_manager_dup_singleton ();
333         have_log = tpl_log_manager_exists (manager,
334                                                empathy_contact_get_account (contact),
335                                                empathy_contact_get_id (contact),
336                                                FALSE);
337 #endif /* ENABLE_TPL */
338         g_object_unref (manager);
339
340         item = gtk_image_menu_item_new_with_mnemonic (_("_Previous Conversations"));
341         image = gtk_image_new_from_icon_name (EMPATHY_IMAGE_LOG,
342                                               GTK_ICON_SIZE_MENU);
343         gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
344         gtk_widget_set_sensitive (item, have_log);
345         gtk_widget_show (image);
346
347         g_signal_connect_swapped (item, "activate",
348                                   G_CALLBACK (contact_log_menu_item_activate_cb),
349                                   contact);
350
351         return item;
352 }
353
354 GtkWidget *
355 empathy_contact_file_transfer_menu_item_new (EmpathyContact *contact)
356 {
357         GtkWidget         *item;
358         GtkWidget         *image;
359
360         g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL);
361
362         item = gtk_image_menu_item_new_with_mnemonic (_("Send file"));
363         image = gtk_image_new_from_icon_name (EMPATHY_IMAGE_DOCUMENT_SEND,
364                                               GTK_ICON_SIZE_MENU);
365         gtk_widget_set_sensitive (item, empathy_contact_can_send_files (contact));
366         gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
367         gtk_widget_show (image);
368
369         g_signal_connect_swapped (item, "activate",
370                                   G_CALLBACK (empathy_send_file_with_file_chooser),
371                                   contact);
372
373         return item;
374 }
375
376 /* FIXME  we should check if the contact supports vnc stream tube */
377 GtkWidget *
378 empathy_contact_share_my_desktop_menu_item_new (EmpathyContact *contact)
379 {
380         GtkWidget         *item;
381         GtkWidget         *image;
382
383         g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL);
384
385         item = gtk_image_menu_item_new_with_mnemonic (_("Share my desktop"));
386         image = gtk_image_new_from_icon_name (GTK_STOCK_NETWORK,
387                                               GTK_ICON_SIZE_MENU);
388         gtk_widget_set_sensitive (item, empathy_contact_can_use_stream_tube (contact));
389         gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
390         gtk_widget_show (image);
391
392         g_signal_connect_swapped (item, "activate",
393                                   G_CALLBACK (empathy_share_my_desktop_share_with_contact),
394                                   contact);
395
396         return item;
397 }
398
399 static void
400 contact_info_menu_item_activate_cb (EmpathyContact *contact)
401 {
402         empathy_contact_information_dialog_show (contact, NULL);
403 }
404
405 GtkWidget *
406 empathy_contact_info_menu_item_new (EmpathyContact *contact)
407 {
408         GtkWidget *item;
409         GtkWidget *image;
410
411         g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL);
412
413         item = gtk_image_menu_item_new_with_mnemonic (_("Infor_mation"));
414         image = gtk_image_new_from_icon_name (EMPATHY_IMAGE_CONTACT_INFORMATION,
415                                               GTK_ICON_SIZE_MENU);
416         gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
417         gtk_widget_show (image);
418
419         g_signal_connect_swapped (item, "activate",
420                                   G_CALLBACK (contact_info_menu_item_activate_cb),
421                                   contact);
422
423         return item;
424 }
425
426 static void
427 contact_edit_menu_item_activate_cb (EmpathyContact *contact)
428 {
429         empathy_contact_edit_dialog_show (contact, NULL);
430 }
431
432 GtkWidget *
433 empathy_contact_edit_menu_item_new (EmpathyContact *contact)
434 {
435         EmpathyContactManager *manager;
436         GtkWidget *item;
437         GtkWidget *image;
438         gboolean enable = FALSE;
439
440         g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL);
441
442         if (empathy_contact_manager_initialized ()) {
443                 TpConnection *connection;
444                 EmpathyContactListFlags flags;
445
446                 manager = empathy_contact_manager_dup_singleton ();
447                 connection = empathy_contact_get_connection (contact);
448                 flags = empathy_contact_manager_get_flags_for_connection (
449                                 manager, connection);
450
451                 enable = (flags & EMPATHY_CONTACT_LIST_CAN_ALIAS ||
452                           flags & EMPATHY_CONTACT_LIST_CAN_GROUP);
453
454                 g_object_unref (manager);
455         }
456
457         item = gtk_image_menu_item_new_with_mnemonic (
458                                                      C_("Edit contact (contextual menu)",
459                                                         "_Edit"));
460         image = gtk_image_new_from_icon_name (GTK_STOCK_EDIT,
461                                               GTK_ICON_SIZE_MENU);
462         gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
463         gtk_widget_show (image);
464
465         gtk_widget_set_sensitive (item, enable);
466
467         g_signal_connect_swapped (item, "activate",
468                                   G_CALLBACK (contact_edit_menu_item_activate_cb),
469                                   contact);
470
471         return item;
472 }
473
474 typedef struct  {
475         EmpathyContact *contact;
476         EmpathyChatroom *chatroom;
477 } RoomSubMenuData;
478
479 static RoomSubMenuData *
480 room_sub_menu_data_new (EmpathyContact *contact,
481                         EmpathyChatroom *chatroom)
482 {
483         RoomSubMenuData *data;
484
485         data = g_slice_new (RoomSubMenuData);
486         data->contact = g_object_ref (contact);
487         data->chatroom = g_object_ref (chatroom);
488         return data;
489 }
490
491 static void
492 room_sub_menu_data_free (RoomSubMenuData *data)
493 {
494         g_object_unref (data->contact);
495         g_object_unref (data->chatroom);
496         g_slice_free (RoomSubMenuData, data);
497 }
498
499 static void
500 room_sub_menu_activate_cb (GtkWidget *item,
501                            RoomSubMenuData *data)
502 {
503         EmpathyTpChat *chat;
504
505         chat = empathy_chatroom_get_tp_chat (data->chatroom);
506         if (chat == NULL) {
507                 /* channel was invalidated. Ignoring */
508                 return;
509         }
510
511         /* send invitation */
512         empathy_contact_list_add (EMPATHY_CONTACT_LIST (chat), data->contact,
513                 _("Inviting you to this room"));
514 }
515
516 static GtkWidget *
517 create_room_sub_menu (EmpathyContact *contact,
518                       EmpathyChatroom *chatroom)
519 {
520         GtkWidget *item;
521         RoomSubMenuData *data;
522
523         item = gtk_menu_item_new_with_label (empathy_chatroom_get_name (chatroom));
524         data = room_sub_menu_data_new (contact, chatroom);
525         g_signal_connect_data (item, "activate",
526                                G_CALLBACK (room_sub_menu_activate_cb), data,
527                                (GClosureNotify) room_sub_menu_data_free, 0);
528
529         return item;
530 }
531
532 GtkWidget *
533 empathy_contact_invite_menu_item_new (EmpathyContact *contact)
534 {
535         GtkWidget *item;
536         GtkWidget *image;
537         GtkWidget *room_item;
538         EmpathyChatroomManager *mgr;
539         GList *rooms, *l;
540         GtkWidget *submenu = NULL;
541
542         g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL);
543
544         item = gtk_image_menu_item_new_with_mnemonic (_("_Invite to chat room"));
545         image = gtk_image_new_from_icon_name (EMPATHY_IMAGE_GROUP_MESSAGE,
546                                               GTK_ICON_SIZE_MENU);
547         gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
548
549         mgr = empathy_chatroom_manager_dup_singleton (NULL);
550         rooms = empathy_chatroom_manager_get_chatrooms (mgr,
551                 empathy_contact_get_account (contact));
552
553         for (l = rooms; l != NULL; l = g_list_next (l)) {
554                 EmpathyChatroom *chatroom = l->data;
555
556                 if (empathy_chatroom_get_tp_chat (chatroom) != NULL) {
557                         if (G_UNLIKELY (submenu == NULL))
558                                 submenu = gtk_menu_new ();
559
560                         room_item = create_room_sub_menu (contact, chatroom);
561                         gtk_menu_shell_append ((GtkMenuShell *) submenu, room_item);
562                         gtk_widget_show (room_item);
563                 }
564         }
565
566         if (submenu) {
567                 gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), submenu);
568         } else {
569                 gtk_widget_set_sensitive (item, FALSE);
570         }
571
572         gtk_widget_show (image);
573
574         g_object_unref (mgr);
575         g_list_free (rooms);
576
577         return item;
578 }
579