friendlist.c 36.4 KB
Newer Older
aymeric's avatar
aymeric committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
/*
linphone, gtk-glade interface.
Copyright (C) 2008  Simon MORLAT (simon.morlat@linphone.org)

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/

#include "linphone.h"

static GtkWidget *linphone_gtk_create_contact_menu(GtkWidget *contact_list);

enum{
	FRIEND_PRESENCE_IMG,
	FRIEND_NAME,
	FRIEND_ID,
28
	FRIEND_CHATROOM,
aymeric's avatar
aymeric committed
29
	FRIEND_SIP_ADDRESS,
30
	FRIEND_CHAT,
31
	FRIEND_CALL_BUTTON_VISIBLE,
32
	FRIEND_CHAT_BUTTON_VISIBLE,
aymeric's avatar
aymeric committed
33 34 35 36 37 38 39 40 41
	FRIEND_LIST_NCOL
};

typedef struct _status_picture_tab_t{
	LinphoneOnlineStatus status;
	const char *img;
} status_picture_tab_t;

status_picture_tab_t status_picture_tab[]={
42 43 44 45 46 47 48 49 50 51 52 53
	{ LinphoneStatusOnline       , "linphone-status-online"       },
	{ LinphoneStatusBusy         , "linphone-status-away"         },
	{ LinphoneStatusBeRightBack  , "linphone-status-away"         },
	{ LinphoneStatusAway         , "linphone-status-away"         },
	{ LinphoneStatusOnThePhone   , "linphone-status-away"         },
	{ LinphoneStatusOutToLunch   , "linphone-status-away"         },
	{ LinphoneStatusDoNotDisturb , "linphone-status-donotdisturb" },
	{ LinphoneStatusMoved        , "linphone-status-away"         },
	{ LinphoneStatusAltService   , "linphone-status-away"         },
	{ LinphoneStatusOffline      , "linphone-status-offline"      },
	{ LinphoneStatusPending      , "linphone-status-offline"      },
	{ LinphoneStatusEnd          , NULL                           }
aymeric's avatar
aymeric committed
54 55
};

56
static const char *status_to_icon_name(LinphoneOnlineStatus ss) {
aymeric's avatar
aymeric committed
57 58
	status_picture_tab_t *t=status_picture_tab;
	while(t->img!=NULL){
59 60
		if (ss==t->status) {
			return t->img;
aymeric's avatar
aymeric committed
61 62 63
		}
		++t;
	}
64
	g_error("No icon name defined for status %i",ss);
aymeric's avatar
aymeric committed
65 66 67
	return NULL;
}

68 69 70 71
static GtkWidget *create_status_picture(LinphoneOnlineStatus ss, GtkIconSize icon_size){
	const char *icon_name = status_to_icon_name(ss);
	if(icon_name) return gtk_image_new_from_icon_name(icon_name, icon_size);
	else return NULL;
72 73
}

74 75 76 77 78 79 80 81 82
gboolean linphone_gtk_friend_list_is_contact(const LinphoneAddress *addr){
	LinphoneFriend *lf;
	char *addr_str=linphone_address_as_string(addr);
	lf=linphone_core_get_friend_by_address(linphone_gtk_get_core(),addr_str);
	if(lf == NULL){
		return FALSE;
	} return TRUE;
}

aymeric's avatar
aymeric committed
83 84 85 86 87 88 89 90 91 92
static void linphone_gtk_set_selection_to_uri_bar(GtkTreeView *treeview){
	GtkTreeSelection *select;
	GtkTreeIter iter;
	GtkTreeModel *model;
	LinphoneFriend *lf=NULL;
	gchar* friend;
	select = gtk_tree_view_get_selection (treeview);
	if (gtk_tree_selection_get_selected (select, &model, &iter))
	{
		gtk_tree_model_get (model, &iter,FRIEND_ID , &lf, -1);
93
		friend=linphone_address_as_string(linphone_friend_get_address(lf));
aymeric's avatar
aymeric committed
94 95 96 97 98
		gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"uribar")),friend);
		ms_free(friend);
	}
}

99
void linphone_gtk_add_contact(void){
100
	GtkWidget *w=linphone_gtk_create_window("contact", linphone_gtk_get_main_window());
101
	int presence_enabled=linphone_gtk_get_ui_config_int("use_subscribe_notify",1);
102

103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(w,"show_presence")),presence_enabled);
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(w,"allow_presence")),
					presence_enabled);
	gtk_widget_show(w);
}

void linphone_gtk_edit_contact(GtkWidget *button){
	GtkWidget *w=gtk_widget_get_toplevel(button);
	GtkTreeSelection *select;
	GtkTreeIter iter;
	GtkTreeModel *model;
	LinphoneFriend *lf=NULL;
	select = gtk_tree_view_get_selection(GTK_TREE_VIEW(linphone_gtk_get_widget(w,"contact_list")));
	if (gtk_tree_selection_get_selected (select, &model, &iter))
	{
		gtk_tree_model_get (model, &iter,FRIEND_ID , &lf, -1);
119
		linphone_gtk_show_contact(lf, w);
120 121 122 123 124 125 126 127 128
	}
}

void linphone_gtk_remove_contact(GtkWidget *button){
	GtkWidget *w=gtk_widget_get_toplevel(button);
	GtkTreeSelection *select;
	GtkTreeIter iter;
	GtkTreeModel *model;
	LinphoneFriend *lf=NULL;
129
	LinphoneChatRoom *cr=NULL;
130 131 132 133 134
	select = gtk_tree_view_get_selection(GTK_TREE_VIEW(linphone_gtk_get_widget(w,"contact_list")));
	if (gtk_tree_selection_get_selected (select, &model, &iter))
	{
		gtk_tree_model_get (model, &iter,FRIEND_ID , &lf, -1);
		linphone_core_remove_friend(linphone_gtk_get_core(),lf);
135 136
		gtk_tree_model_get (model, &iter,FRIEND_CHATROOM , &cr, -1);
		linphone_chat_room_delete_history(cr);
137 138 139 140
		linphone_gtk_show_friends();
	}
}

Margaux Clerc's avatar
Margaux Clerc committed
141
void linphone_gtk_delete_history(GtkWidget *button){
142
	GtkWidget *w=linphone_gtk_get_main_window();
Margaux Clerc's avatar
Margaux Clerc committed
143 144 145
	GtkTreeSelection *select;
	GtkTreeIter iter;
	GtkTreeModel *model;
146
	GtkWidget *chat_view;
Margaux Clerc's avatar
Margaux Clerc committed
147
	LinphoneFriend *lf=NULL;
148
	GtkWidget *friendlist;
149

150 151 152
	friendlist=linphone_gtk_get_widget(w,"contact_list");
	chat_view=(GtkWidget *)g_object_get_data(G_OBJECT(friendlist),"chatview");
	select = gtk_tree_view_get_selection(GTK_TREE_VIEW(friendlist));
Margaux Clerc's avatar
Margaux Clerc committed
153 154
	if (gtk_tree_selection_get_selected (select, &model, &iter))
	{
Simon Morlat's avatar
Simon Morlat committed
155
		LinphoneChatRoom *cr;
Margaux Clerc's avatar
Margaux Clerc committed
156
		gtk_tree_model_get (model, &iter,FRIEND_ID , &lf, -1);
157
		gtk_tree_model_get (model, &iter,FRIEND_CHATROOM , &cr, -1);
Simon Morlat's avatar
Simon Morlat committed
158
		linphone_chat_room_delete_history(cr);
159
		if(chat_view!=NULL){
160 161 162
			const LinphoneAddress *from=linphone_gtk_friend_list_get_active_address();
			const LinphoneAddress *addr=linphone_friend_get_address(lf);
			if(linphone_address_weak_equal(from,addr)){
163 164 165 166
				GtkTextView *text_view=GTK_TEXT_VIEW(linphone_gtk_get_widget(chat_view,"textview"));
				GtkTextIter start;
				GtkTextIter end;
				GtkTextBuffer *text_buffer;
167

168 169 170 171 172 173
				text_buffer=gtk_text_view_get_buffer(text_view);
				gtk_text_buffer_get_bounds(text_buffer, &start, &end);
				gtk_text_buffer_delete (text_buffer, &start, &end);
				g_object_set_data(G_OBJECT(chat_view),"from_message",NULL);
			}
		}
Margaux Clerc's avatar
Margaux Clerc committed
174 175 176 177
		linphone_gtk_show_friends();
	}
}

aymeric's avatar
aymeric committed
178 179 180 181 182 183
static void linphone_gtk_call_selected(GtkTreeView *treeview){
	linphone_gtk_set_selection_to_uri_bar(treeview);
	linphone_gtk_start_call(linphone_gtk_get_widget(gtk_widget_get_toplevel(GTK_WIDGET(treeview)),
					"start_call"));
}

184
void linphone_gtk_friend_list_update_button_display(GtkTreeView *friendlist){
185
	GtkTreeIter iter, selected_iter;
186 187
	GtkTreeModel *model=gtk_tree_view_get_model(friendlist);
	GtkTreeSelection *select=gtk_tree_view_get_selection(friendlist);
Margaux Clerc's avatar
Margaux Clerc committed
188
	LinphoneChatRoom *cr=NULL;
189
	gboolean is_composing;
Margaux Clerc's avatar
Margaux Clerc committed
190
	int nbmsg=0;
191
	GtkTreePath *selected_path = NULL;
192
	GtkTreePath *hovered_row = (GtkTreePath *)g_object_get_data(G_OBJECT(friendlist), "hovered_row");
193

194 195 196
	if (gtk_tree_selection_get_selected(select, &model, &selected_iter)){
		selected_path = gtk_tree_model_get_path(model, &selected_iter);
	}
197

198 199
	if (gtk_tree_model_get_iter_first(model,&iter)) {
		do{
200
			const char *icon_name = NULL;
201 202 203
			gboolean show_chat_button = FALSE;
			gboolean show_call_button = FALSE;
			GtkTreePath *path = gtk_tree_model_get_path(model, &iter);
204

205
			gtk_tree_model_get (model, &iter,FRIEND_CHATROOM , &cr, -1);
Margaux Clerc's avatar
Margaux Clerc committed
206
			nbmsg=linphone_chat_room_get_unread_messages_count(cr);
207
			is_composing=linphone_chat_room_is_remote_composing(cr);
Margaux Clerc's avatar
Margaux Clerc committed
208
			if(nbmsg != 0){
209
				if (is_composing) icon_name = "linphone-chat-new-message-and-writing";
210
				else icon_name = "linphone-chat-new-message";
211
				show_chat_button = TRUE;
Margaux Clerc's avatar
Margaux Clerc committed
212
			} else {
213
				if (is_composing) {
214
					icon_name = "linphone-chat-writing";
215 216
					show_chat_button = TRUE;
				} else {
217 218
					icon_name = "linphone-chat-nothing";
				}
Margaux Clerc's avatar
Margaux Clerc committed
219
			}
220
			if ((selected_path && gtk_tree_path_compare(path, selected_path) == 0)
221 222 223 224
					|| (hovered_row && gtk_tree_path_compare(path, hovered_row) == 0)){
				show_chat_button = TRUE;
				show_call_button = TRUE;
			}
225
			gtk_list_store_set(GTK_LIST_STORE(model),&iter,FRIEND_CHAT,icon_name,
226 227
						FRIEND_CHAT_BUTTON_VISIBLE, show_chat_button, -1);
			gtk_list_store_set(GTK_LIST_STORE(model), &iter, FRIEND_CALL_BUTTON_VISIBLE, show_call_button, -1);
228

229
			gtk_tree_path_free(path);
230 231
		}while(gtk_tree_model_iter_next(model,&iter));
	}
232
	if (selected_path) gtk_tree_path_free(selected_path);
233 234
}

235 236 237 238 239
static gboolean grab_focus(GtkWidget *w){
	gtk_widget_grab_focus(w);
	return FALSE;
}

240 241 242
void linphone_gtk_friend_list_set_active_address(const LinphoneAddress *addr){
	GtkWidget *w=linphone_gtk_get_main_window();
	GtkWidget *friendlist=linphone_gtk_get_widget(w,"contact_list");
Simon Morlat's avatar
Simon Morlat committed
243
	g_object_set_data_full(G_OBJECT(friendlist),"from", addr ? linphone_address_clone(addr) : NULL, (GDestroyNotify)linphone_address_destroy);
244 245 246 247 248 249 250 251
}

const LinphoneAddress *linphone_gtk_friend_list_get_active_address(void){
	GtkWidget *w=linphone_gtk_get_main_window();
	GtkWidget *friendlist=linphone_gtk_get_widget(w,"contact_list");
	return (const LinphoneAddress*)g_object_get_data(G_OBJECT(friendlist),"from");
}

Margaux Clerc's avatar
Margaux Clerc committed
252
void linphone_gtk_friend_list_set_chat_conversation(const LinphoneAddress *la){
Margaux Clerc's avatar
Margaux Clerc committed
253
	GtkTreeIter iter;
254 255 256 257 258 259
	GtkListStore *store=NULL;
	GtkWidget *w = linphone_gtk_get_main_window();
	GtkWidget *friendlist=linphone_gtk_get_widget(w,"contact_list");
	GtkTreeModel *model=gtk_tree_view_get_model(GTK_TREE_VIEW(friendlist));
	GtkWidget *chat_view=(GtkWidget*)g_object_get_data(G_OBJECT(friendlist),"chatview");
	LinphoneFriend *lf=NULL;
260 261
	LinphoneChatRoom *cr=NULL;
	GtkNotebook *notebook=(GtkNotebook *)linphone_gtk_get_widget(w,"viewswitch");
262
	GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(friendlist));
263

264
	lf=linphone_core_find_friend(linphone_gtk_get_core(),la);
265 266
	if(lf==NULL){
		cr=linphone_gtk_create_chatroom(la);
267
		linphone_gtk_friend_list_set_active_address(la);
268 269 270 271 272
	} else {
		store=GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(friendlist)));
		if (gtk_tree_model_get_iter_first(model,&iter)) {
			do{
				const LinphoneAddress *uri;
273
				gtk_tree_model_get(model, &iter,FRIEND_ID , &lf, -1);
274
				uri=linphone_friend_get_address(lf);
275
				if (linphone_address_weak_equal(uri,la)){
276 277 278 279 280
					gtk_tree_model_get (model, &iter,FRIEND_CHATROOM , &cr, -1);
					if(cr==NULL){
						cr=linphone_gtk_create_chatroom(uri);
						gtk_list_store_set(store,&iter,FRIEND_CHATROOM,cr,-1);
					}
281
					linphone_gtk_friend_list_set_active_address(uri);
282
					gtk_tree_selection_select_iter(selection, &iter);
283
					break;
Margaux Clerc's avatar
Margaux Clerc committed
284
				}
285 286
			}while(gtk_tree_model_iter_next(model,&iter));
		}
287
	}
288 289 290 291 292 293 294 295 296 297
	if(cr) {
		if(chat_view == NULL){
			chat_view=linphone_gtk_init_chatroom(cr,la);
			g_object_set_data(G_OBJECT(friendlist),"chatview",(gpointer)chat_view);
		} else {
			linphone_gtk_load_chatroom(cr,la,chat_view);
		}
		gtk_notebook_set_current_page(notebook,gtk_notebook_page_num(notebook,chat_view));
		g_idle_add((GSourceFunc)grab_focus,linphone_gtk_get_widget(chat_view,"text_entry"));
	}
298 299 300 301 302 303 304
}

void linphone_gtk_notebook_tab_select(GtkNotebook *notebook,GtkWidget *page,guint page_num, gpointer data){
	GtkWidget *w=linphone_gtk_get_main_window();
	GtkWidget *friendlist=linphone_gtk_get_widget(w,"contact_list");
	GtkWidget *chat_view;
	LinphoneChatRoom *cr=NULL;
Margaux Clerc's avatar
Margaux Clerc committed
305 306 307 308 309 310
 	chat_view=(GtkWidget*)g_object_get_data(G_OBJECT(friendlist),"chatview");
 	if(page != NULL){
 		notebook=(GtkNotebook *)linphone_gtk_get_widget(w,"viewswitch");
 		if(gtk_notebook_page_num(notebook,page)==gtk_notebook_page_num(notebook,chat_view)){
 			cr=g_object_get_data(G_OBJECT(chat_view),"cr");
 			if(cr!=NULL){
311
				linphone_gtk_mark_chat_read(cr);
Margaux Clerc's avatar
Margaux Clerc committed
312
 				linphone_gtk_show_friends();
313
			}
Margaux Clerc's avatar
Margaux Clerc committed
314
 		}
Margaux Clerc's avatar
Margaux Clerc committed
315
	}
316 317
}

318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334
void linphone_gtk_chat_selected(GtkWidget *item){
	GtkWidget *w=gtk_widget_get_toplevel(item);
	GtkTreeSelection *select;
	GtkListStore *store=NULL;
	GtkTreeIter iter;
	GtkTreeModel *model;
	LinphoneFriend *lf=NULL;
	LinphoneChatRoom *cr=NULL;
	GtkWidget *friendlist=linphone_gtk_get_widget(w,"contact_list");
	GtkWidget *page;

	select=gtk_tree_view_get_selection(GTK_TREE_VIEW(friendlist));
	store=GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(item)));
	if (gtk_tree_selection_get_selected (select, &model, &iter)){
		GtkNotebook *notebook=(GtkNotebook *)linphone_gtk_get_widget(w,"viewswitch");
		const LinphoneAddress *uri;
		gtk_tree_model_get (model, &iter,FRIEND_ID , &lf, -1);
Margaux Clerc's avatar
Margaux Clerc committed
335
		gtk_tree_model_get (model, &iter,FRIEND_CHATROOM , &cr, -1);
336
		uri=linphone_friend_get_address(lf);
Margaux Clerc's avatar
Margaux Clerc committed
337
		if(cr==NULL){
338
			cr=linphone_gtk_create_chatroom(uri);
Margaux Clerc's avatar
Margaux Clerc committed
339
			gtk_list_store_set(store,&iter,FRIEND_CHATROOM,cr,-1);
340
		}
341
		page=GTK_WIDGET(g_object_get_data(G_OBJECT(friendlist),"chatview"));
342
		linphone_gtk_friend_list_set_active_address(uri);
343 344 345 346 347 348
		if(page==NULL){
			page=linphone_gtk_init_chatroom(cr,uri);
			g_object_set_data(G_OBJECT(friendlist),"chatview",(gpointer)page);
		} else {
			linphone_gtk_load_chatroom(cr,uri,page);
		}
349
		linphone_gtk_mark_chat_read(cr);
350
		gtk_notebook_set_current_page(notebook,gtk_notebook_page_num(notebook,page));
351
		g_idle_add((GSourceFunc)grab_focus,linphone_gtk_get_widget(page,"text_entry"));
352 353 354
	}
}

355 356
void linphone_gtk_contact_clicked(GtkTreeSelection *selection){
	GtkTreeView *friendlist = gtk_tree_selection_get_tree_view(selection);
357 358 359
	GtkWidget *mw = linphone_gtk_get_main_window();
	GtkWidget *edit_button = linphone_gtk_get_widget(mw, "edit_button");
	GtkWidget *remove_button = linphone_gtk_get_widget(mw, "remove_button");
360

361 362
	linphone_gtk_set_selection_to_uri_bar(friendlist);
	linphone_gtk_friend_list_update_button_display(friendlist);
363 364 365 366 367 368 369
	if(gtk_tree_selection_get_selected(selection, NULL, NULL)) {
		gtk_widget_set_sensitive(edit_button, TRUE);
		gtk_widget_set_sensitive(remove_button, TRUE);
	} else {
		gtk_widget_set_sensitive(edit_button, FALSE);
		gtk_widget_set_sensitive(remove_button, FALSE);
	}
370 371 372 373 374 375 376 377 378 379 380 381 382
}


void linphone_gtk_add_button_clicked(void){
	linphone_gtk_add_contact();
}

void linphone_gtk_edit_button_clicked(GtkWidget *button){
	linphone_gtk_edit_contact(button);
}

void linphone_gtk_remove_button_clicked(GtkWidget *button){
	linphone_gtk_remove_contact(button);
aymeric's avatar
aymeric committed
383 384
}

385
static GtkWidget * create_presence_menu(void){
aymeric's avatar
aymeric committed
386 387 388 389
	GtkWidget *menu=gtk_menu_new();
	GtkWidget *menu_item;
	status_picture_tab_t *t;
	for(t=status_picture_tab;t->img!=NULL;++t){
Simon Morlat's avatar
Simon Morlat committed
390
		if (t->status==LinphoneStatusPending){
aymeric's avatar
aymeric committed
391 392 393 394
			continue;
		}
		menu_item=gtk_image_menu_item_new_with_label(linphone_online_status_to_string(t->status));
		gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),
395
				gtk_image_new_from_icon_name(t->img, GTK_ICON_SIZE_LARGE_TOOLBAR));
aymeric's avatar
aymeric committed
396 397 398 399 400 401 402 403 404
		gtk_widget_show(menu_item);
		gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item);
		g_signal_connect_swapped(G_OBJECT(menu_item),"activate",(GCallback)linphone_gtk_set_my_presence,GINT_TO_POINTER(t->status));
	}
	return menu;
}

void linphone_gtk_set_my_presence(LinphoneOnlineStatus ss){
	GtkWidget *button=linphone_gtk_get_widget(linphone_gtk_get_main_window(),"presence_button");
405
	GtkWidget *image=create_status_picture(ss, GTK_ICON_SIZE_LARGE_TOOLBAR);
aymeric's avatar
aymeric committed
406
	GtkWidget *menu;
407

408
	gtk_widget_set_tooltip_text(button,linphone_online_status_to_string(ss));
aymeric's avatar
aymeric committed
409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427
	gtk_button_set_image(GTK_BUTTON(button),image);
	/*prepare menu*/
	menu=(GtkWidget*)g_object_get_data(G_OBJECT(button),"presence_menu");
	if (menu==NULL){
		menu=create_presence_menu();
		/*the menu is destroyed when the button is destroyed*/
		g_object_weak_ref(G_OBJECT(button),(GWeakNotify)gtk_widget_destroy,menu);
		g_object_set_data(G_OBJECT(button),"presence_menu",menu);
	}
	linphone_core_set_presence_info(linphone_gtk_get_core(),0,NULL,ss);
}

void linphone_gtk_my_presence_clicked(GtkWidget *button){
	GtkWidget *menu=(GtkWidget*)g_object_get_data(G_OBJECT(button),"presence_menu");
	gtk_menu_popup(GTK_MENU(menu),NULL,NULL,NULL,NULL,0,
			gtk_get_current_event_time());
	gtk_widget_show(menu);
}

428
static void icon_press_handler(GtkEntry *entry){
429
	GtkWidget *w = gtk_widget_get_toplevel(GTK_WIDGET(entry));
430 431
	const char *text=gtk_entry_get_text(entry);
	if (text && strlen(text)>0){
432
		LinphoneAddress *addr;
433
		LinphoneFriend *lf;
434 435 436
		char *uri;
		addr=linphone_core_interpret_url(linphone_gtk_get_core(),text);
		if (addr==NULL){
437 438
			return ;
		}
439
		uri=linphone_address_as_string_uri_only(addr);
440
		lf=linphone_core_get_friend_by_address(linphone_gtk_get_core(),uri);
441
		ms_free(uri);
442
		if (lf==NULL)
443
			lf=linphone_core_create_friend(linphone_gtk_get_core());
444
		if (lf!=NULL){
445
			linphone_friend_set_address(lf,addr);
446
			linphone_gtk_show_contact(lf, w);
447
		}
448
		linphone_address_destroy(addr);
449 450 451 452
	}
}

static void update_star(GtkEntry *entry, gboolean is_known){
453
	if (is_known){
454
		gtk_entry_set_icon_from_icon_name(entry,GTK_ENTRY_ICON_SECONDARY,NULL);
455
		gtk_entry_set_icon_sensitive(GTK_ENTRY(entry),GTK_ENTRY_ICON_SECONDARY,FALSE);
456
		gtk_entry_set_icon_tooltip_text(GTK_ENTRY(entry),GTK_ENTRY_ICON_SECONDARY,NULL);
457
	}else{
458
		gtk_entry_set_icon_from_icon_name(entry,GTK_ENTRY_ICON_SECONDARY,"linphone-contact-add");
459
		gtk_entry_set_icon_sensitive(GTK_ENTRY(entry),GTK_ENTRY_ICON_SECONDARY,TRUE);
460
		gtk_entry_set_icon_tooltip_text(GTK_ENTRY(entry),GTK_ENTRY_ICON_SECONDARY,_("Add to addressbook"));
461 462 463 464
	}
}

static void check_contact(GtkEditable *editable, LinphoneCore *lc){
465
	bool_t known = TRUE;
466 467 468 469
	char *tmp = gtk_editable_get_chars(editable, 0, -1);
	if (tmp != NULL) {
		if (strlen(tmp) > 0) {
			known = linphone_gtk_is_friend(lc, tmp);
470 471 472
		}
		g_free(tmp);
	}
473
	update_star(GTK_ENTRY(editable), known);
474 475 476
}

static void linphone_gtk_init_bookmark_icon(void){
477
	GtkWidget *entry = linphone_gtk_get_widget(linphone_gtk_get_main_window(), "uribar");
478 479 480
	g_signal_connect(G_OBJECT(entry),"icon-release",(GCallback)icon_press_handler,NULL);
	g_signal_connect(G_OBJECT(GTK_EDITABLE(entry)),"changed",(GCallback)check_contact,linphone_gtk_get_core());
}
aymeric's avatar
aymeric committed
481

482 483 484 485 486 487 488 489
static gboolean friend_search_func(GtkTreeModel *model, gint column,
                                                         const gchar *key,
                                                         GtkTreeIter *iter,
                                                         gpointer search_data){
	char *name=NULL;
	gboolean ret=TRUE;
	gtk_tree_model_get(model,iter,FRIEND_NAME,&name,-1);
	if (name!=NULL){
Margaux Clerc's avatar
Margaux Clerc committed
490 491 492 493 494
		gchar *uname=g_utf8_casefold(name,-1); /* need that to perform case-insensitive search in utf8 */
		gchar *ukey=g_utf8_casefold(key,-1);
		ret=strstr(uname,ukey)==NULL;
		g_free(uname);
		g_free(ukey);
495 496 497 498 499
		g_free(name);
	}
	return ret;
}

500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519
static gint friend_sort(GtkTreeModel *model, GtkTreeIter *a,GtkTreeIter *b,gpointer user_data){
	char *n1=NULL,*n2=NULL;
	int ret;
	gtk_tree_model_get(model,a,FRIEND_NAME,&n1,-1);
	gtk_tree_model_get(model,b,FRIEND_NAME,&n2,-1);
	if (n1 && n2) {
		ret=strcmp(n1,n2);
		g_free(n1);
		g_free(n2);
	}else if (n1){
		g_free(n1);
		ret=-1;
	}else if (n2){
		g_free(n2);
		ret=1;
	}else ret=0;
	return ret;
}

void linphone_gtk_friend_list_on_name_column_clicked(GtkTreeModel *model){
520 521
	GtkSortType st;
	gint column;
522

523 524 525 526 527 528 529 530 531 532
	gtk_tree_sortable_get_sort_column_id(GTK_TREE_SORTABLE(model),&column,&st);
	if (column==FRIEND_NAME){
		if (st==GTK_SORT_ASCENDING) st=GTK_SORT_DESCENDING;
		else st=GTK_SORT_ASCENDING;
	}else st=GTK_SORT_ASCENDING;
	gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(model),FRIEND_NAME,st);
}

static int get_friend_weight(const LinphoneFriend *lf){
	int w=0;
533 534
	LinphoneCore *lc=linphone_gtk_get_core();
	LinphoneChatRoom *cr=linphone_core_get_chat_room(lc,linphone_friend_get_address(lf));
535

536 537 538
	if (cr && linphone_chat_room_get_unread_messages_count(cr)>0){
		w+=2000;
	}
539

540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563
	switch(linphone_friend_get_status(lf)){
		case LinphoneStatusOnline:
			w+=1000;
		break;
		case LinphoneStatusOffline:
			if (linphone_friend_get_send_subscribe(lf))
				w+=100;
		break;
		default:
			w+=500;
		break;
	}
	return w;
}

static int friend_compare_func(const LinphoneFriend *lf1, const LinphoneFriend *lf2){
	int w1,w2;
	w1=get_friend_weight(lf1);
	w2=get_friend_weight(lf2);
	if (w1==w2){
		const char *u1,*u2;
		const LinphoneAddress *addr1,*addr2;
		addr1=linphone_friend_get_address(lf1);
		addr2=linphone_friend_get_address(lf2);
564 565
		u1=linphone_address_get_username(addr1);
		u2=linphone_address_get_username(addr2);
566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584
		if (u1 && u2) return strcasecmp(u1,u2);
		if (u1) return 1;
		else return -1;
	}
	return w2-w1;
}

static MSList *sort_friend_list(const MSList *friends){
	MSList *ret=NULL;
	const MSList *elem;
	LinphoneFriend *lf;

	for(elem=friends;elem!=NULL;elem=elem->next){
		lf=(LinphoneFriend*)elem->data;
		ret=ms_list_insert_sorted(ret,lf,(MSCompareFunc)friend_compare_func);
	}
	return ret;
}

585 586
#if 0
void linphone_gtk_friend_list_on_presence_column_clicked(GtkTreeModel *model){
587 588
	GtkSortType st;
	gint column;
589

590 591 592 593 594 595 596
	gtk_tree_sortable_get_sort_column_id(GTK_TREE_SORTABLE(model),&column,&st);
	if (column==FRIEND_ID){
		if (st==GTK_SORT_ASCENDING) st=GTK_SORT_DESCENDING;
		else st=GTK_SORT_ASCENDING;
	}else st=GTK_SORT_ASCENDING;
	gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(model),FRIEND_ID,st);
}
597
#endif
598

599
static void linphone_gtk_friend_list_init(GtkWidget *friendlist){
600
	GtkTreeModel *store = gtk_tree_view_get_model(GTK_TREE_VIEW(friendlist));
601
	GtkTreeSelection *select = gtk_tree_view_get_selection (GTK_TREE_VIEW (friendlist));
602 603

	linphone_gtk_init_bookmark_icon();
604
	gtk_tree_view_set_search_equal_func(GTK_TREE_VIEW(friendlist),friend_search_func,NULL,NULL);
605
	gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(store),FRIEND_NAME,friend_sort,NULL,NULL);
aymeric's avatar
aymeric committed
606
	gtk_tree_selection_set_mode (select, GTK_SELECTION_SINGLE);
607
	g_signal_connect(G_OBJECT(select), "changed", G_CALLBACK(linphone_gtk_contact_clicked), NULL);
608

609
	g_object_set_data(G_OBJECT(friendlist), "friendlist_initialized", (gpointer)TRUE);
aymeric's avatar
aymeric committed
610 611
}

612 613 614 615 616 617
void linphone_gtk_show_directory_search(void){
	LinphoneProxyConfig *cfg=NULL;
	SipSetupContext * ssc=NULL;
	GtkWidget *mw=linphone_gtk_get_main_window();
	GtkWidget *search_box=linphone_gtk_get_widget(mw,"directory_search_box");

jehan's avatar
jehan committed
618
	cfg = linphone_core_get_default_proxy_config(linphone_gtk_get_core());
619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653
	if (cfg){
		ssc=linphone_proxy_config_get_sip_setup_context(cfg);
		if (ssc!=NULL && sip_setup_context_get_capabilities(ssc) & SIP_SETUP_CAP_BUDDY_LOOKUP){
			GtkWidget *entry=linphone_gtk_get_widget(mw,"directory_search_entry");
			gchar  *tooltip;
			GdkColor grey={0,40000,40000,40000};
			gtk_widget_show(search_box);
			tooltip=g_strdup_printf(_("Search in %s directory"),linphone_proxy_config_get_domain(cfg));
			gtk_widget_modify_text(entry,GTK_STATE_NORMAL,&grey);
			gtk_entry_set_text(GTK_ENTRY(entry),tooltip);
			g_object_set_data(G_OBJECT(entry),"active",GINT_TO_POINTER(0));
			g_free(tooltip);
			return;
		}
	}
	gtk_widget_hide(search_box);
}

gboolean linphone_gtk_directory_search_focus_out(GtkWidget *entry){
	if (gtk_entry_get_text_length(GTK_ENTRY(entry))==0)
		linphone_gtk_show_directory_search();
	return FALSE;
}

gboolean linphone_gtk_directory_search_focus_in(GtkWidget *entry){
	if (GPOINTER_TO_INT(g_object_get_data(G_OBJECT(entry),"active"))==0){
		gtk_entry_set_text(GTK_ENTRY(entry),"");
		gtk_widget_modify_text(entry,GTK_STATE_NORMAL,NULL);
		g_object_set_data(G_OBJECT(entry),"active",GINT_TO_POINTER(1));
	}
	return FALSE;
}

void linphone_gtk_directory_search_activate(GtkWidget *entry){
	LinphoneProxyConfig *cfg;
654
	GtkWidget *w;
655
	cfg = linphone_core_get_default_proxy_config(linphone_gtk_get_core());
656
	w=linphone_gtk_show_buddy_lookup_window(linphone_proxy_config_get_sip_setup_context(cfg));
smorlat's avatar
smorlat committed
657 658
	if (GPOINTER_TO_INT(g_object_get_data(G_OBJECT(entry),"active"))==1)
		linphone_gtk_buddy_lookup_set_keyword(w,gtk_entry_get_text(GTK_ENTRY(entry)));
659 660 661 662 663 664 665
}

void linphone_gtk_directory_search_button_clicked(GtkWidget *button){
	linphone_gtk_directory_search_activate(
		linphone_gtk_get_widget(gtk_widget_get_toplevel(button),"directory_search_entry"));
}

aymeric's avatar
aymeric committed
666 667 668 669 670 671 672
void linphone_gtk_show_friends(void){
	GtkWidget *mw=linphone_gtk_get_main_window();
	GtkWidget *friendlist=linphone_gtk_get_widget(mw,"contact_list");
	GtkListStore *store=NULL;
	GtkTreeIter iter;
	const MSList *itf;
	LinphoneCore *core=linphone_gtk_get_core();
673
	MSList *sorted;
Margaux Clerc's avatar
Margaux Clerc committed
674
	LinphoneChatRoom *cr=NULL;
675

676
	linphone_gtk_show_directory_search();
677
	if (!g_object_get_data(G_OBJECT(friendlist), "friendlist_initialized")) {
aymeric's avatar
aymeric committed
678 679
		linphone_gtk_friend_list_init(friendlist);
	}
680

aymeric's avatar
aymeric committed
681 682 683
	store=GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(friendlist)));
	gtk_list_store_clear(store);

684 685 686
	sorted=sort_friend_list(linphone_core_get_friend_list(core));

	for(itf=sorted;itf!=NULL;itf=ms_list_next(itf)){
aymeric's avatar
aymeric committed
687
		LinphoneFriend *lf=(LinphoneFriend*)itf->data;
688
		const LinphoneAddress *f_uri=linphone_friend_get_address(lf);
689
		char *uri=linphone_address_as_string(f_uri);
690
		const char *name=linphone_friend_get_name(lf);
691
		const char *display=name;
aymeric's avatar
aymeric committed
692
		char *escaped=NULL;
Margaux Clerc's avatar
Margaux Clerc committed
693 694
		int nbmsg=0;

695 696
		//BuddyInfo *bi;
		gboolean send_subscribe=linphone_friend_get_send_subscribe(lf);
697
		if (display==NULL || display[0]=='\0') {
698
			display=linphone_address_get_username(f_uri);
aymeric's avatar
aymeric committed
699
		}
700 701
		gtk_list_store_append(store,&iter);
		gtk_list_store_set(store,&iter,FRIEND_NAME, display,FRIEND_ID,lf,
702
				FRIEND_PRESENCE_IMG, send_subscribe ? status_to_icon_name(linphone_friend_get_status(lf)) : NULL,
703
				FRIEND_CHAT,"linphone-chat-nothing", -1);
704 705 706 707
		cr=linphone_gtk_create_chatroom(f_uri);
		gtk_list_store_set(store,&iter,FRIEND_CHATROOM,cr,-1);
		nbmsg=linphone_chat_room_get_unread_messages_count(cr);
		if(nbmsg != 0){
708
			gtk_list_store_set(store,&iter,FRIEND_CHAT,"linphone-chat-new-message",-1);
Margaux Clerc's avatar
Margaux Clerc committed
709
		}
710 711 712
		escaped=g_markup_escape_text(uri,-1);
		gtk_list_store_set(store,&iter,FRIEND_SIP_ADDRESS,escaped,-1);
		g_free(escaped);
aymeric's avatar
aymeric committed
713 714
		ms_free(uri);
	}
715
	ms_list_free(sorted);
aymeric's avatar
aymeric committed
716 717
}

718
void linphone_gtk_show_contact(LinphoneFriend *lf, GtkWidget *parent){
719
	GtkWidget *w = linphone_gtk_create_window("contact", parent);
720
	char *uri;
721
	const char *name = linphone_friend_get_name(lf);
722 723
	const LinphoneAddress *f_uri = linphone_friend_get_address(lf);
	
724
	uri=linphone_address_as_string_uri_only(f_uri);
aymeric's avatar
aymeric committed
725 726 727 728
	if (uri) {
		gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(w,"sip_address")),uri);
		ms_free(uri);
	}
729
	
aymeric's avatar
aymeric committed
730 731 732
	if (name){
		gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(w,"name")),name);
	}
733
	
aymeric's avatar
aymeric committed
734 735 736 737 738
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(w,"show_presence")),
					linphone_friend_get_send_subscribe(lf));
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(w,"allow_presence")),
					linphone_friend_get_inc_subscribe_policy(lf)==LinphoneSPAccept);
	g_object_set_data(G_OBJECT(w),"friend_ref",(gpointer)lf);
739

aymeric's avatar
aymeric committed
740 741 742 743 744 745 746 747 748 749
	gtk_widget_show(w);
}

void linphone_gtk_contact_cancel(GtkWidget *button){
	gtk_widget_destroy(gtk_widget_get_toplevel(button));
}

void linphone_gtk_contact_ok(GtkWidget *button){
	GtkWidget *w=gtk_widget_get_toplevel(button);
	LinphoneFriend *lf=(LinphoneFriend*)g_object_get_data(G_OBJECT(w),"friend_ref");
750
	LinphoneFriend *lf2;
751
	gboolean show_presence=FALSE,allow_presence=FALSE;
aymeric's avatar
aymeric committed
752
	const gchar *name,*uri;
753
	LinphoneAddress* friend_address;
aymeric's avatar
aymeric committed
754
	if (lf==NULL){
755
		lf=linphone_core_create_friend(linphone_gtk_get_core());
756 757 758 759 760 761
		if (linphone_gtk_get_ui_config_int("use_subscribe_notify",1)==1){
			show_presence=FALSE;
			allow_presence=FALSE;
		}
		linphone_friend_set_inc_subscribe_policy(lf,allow_presence ? LinphoneSPAccept : LinphoneSPDeny);
		linphone_friend_send_subscribe(lf,show_presence);
aymeric's avatar
aymeric committed
762
	}
Margaux Clerc's avatar
Margaux Clerc committed
763 764 765 766 767

	name = NULL;
	if(gtk_entry_get_text_length(GTK_ENTRY(linphone_gtk_get_widget(w,"name"))) != 0){
		name=gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(w,"name")));
	}
aymeric's avatar
aymeric committed
768 769 770
	uri=gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(w,"sip_address")));
	show_presence=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(w,"show_presence")));
	allow_presence=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(w,"allow_presence")));
771 772
	friend_address=linphone_core_interpret_url(linphone_gtk_get_core(),uri);
	if (friend_address==NULL){
smorlat's avatar
smorlat committed
773 774 775
		linphone_gtk_display_something(GTK_MESSAGE_WARNING,_("Invalid sip contact !"));
		return ;
	}
Margaux Clerc's avatar
Margaux Clerc committed
776

Ghislain MARY's avatar
Ghislain MARY committed
777
	linphone_friend_set_address(lf,friend_address);
778
	linphone_friend_set_name(lf,name);
aymeric's avatar
aymeric committed
779 780
	linphone_friend_send_subscribe(lf,show_presence);
	linphone_friend_set_inc_subscribe_policy(lf,allow_presence==TRUE ? LinphoneSPAccept : LinphoneSPDeny);
smorlat's avatar
smorlat committed
781
	if (linphone_friend_in_list(lf)) {
aymeric's avatar
aymeric committed
782
		linphone_friend_done(lf);
783
	} else {
784 785 786
		char *uri=linphone_address_as_string_uri_only(friend_address);
		lf2=linphone_core_get_friend_by_address(linphone_gtk_get_core(),uri);
		ms_free(uri);
787 788 789
		if(lf2==NULL){
			linphone_core_add_friend(linphone_gtk_get_core(),lf);
		}
aymeric's avatar
aymeric committed
790
	}
791
	linphone_address_destroy(friend_address);
aymeric's avatar
aymeric committed
792 793 794 795 796 797 798
	linphone_gtk_show_friends();
	gtk_widget_destroy(w);
}

static GtkWidget *linphone_gtk_create_contact_menu(GtkWidget *contact_list){
	GtkWidget *menu=gtk_menu_new();
	GtkWidget *menu_item;
smorlat's avatar
smorlat committed
799 800
	gchar *edit_label=NULL;
	gchar *delete_label=NULL;
Margaux Clerc's avatar
Margaux Clerc committed
801
	gchar *delete_hist_label=NULL;
802
	gchar *add_contact_label=NULL;
aymeric's avatar
aymeric committed
803 804 805 806 807
	gchar *name=NULL;
	GtkTreeSelection *select;
	GtkTreeIter iter;
	GtkTreeModel *model;
	GtkWidget *image;
smorlat's avatar
smorlat committed
808 809 810
	LinphoneCore *lc=linphone_gtk_get_core();
	LinphoneProxyConfig *cfg=NULL;
	SipSetupContext * ssc=NULL;
811
	bool_t show_menu_separator=FALSE;
812

813
	cfg = linphone_core_get_default_proxy_config(lc);
smorlat's avatar
smorlat committed
814 815 816
	if (cfg){
		ssc=linphone_proxy_config_get_sip_setup_context(cfg);
	}
smorlat's avatar
smorlat committed
817

aymeric's avatar
aymeric committed
818 819
	g_signal_connect(G_OBJECT(menu), "selection-done", G_CALLBACK (gtk_widget_destroy), NULL);
	select = gtk_tree_view_get_selection(GTK_TREE_VIEW(contact_list));
820
	add_contact_label=g_strdup_printf(_("Add a new contact"));
aymeric's avatar
aymeric committed
821 822
	if (gtk_tree_selection_get_selected (select, &model, &iter)){
		gtk_tree_model_get(model, &iter,FRIEND_NAME , &name, -1);
smorlat's avatar
smorlat committed
823 824
		edit_label=g_strdup_printf(_("Edit contact '%s'"),name);
		delete_label=g_strdup_printf(_("Delete contact '%s'"),name);
Margaux Clerc's avatar
Margaux Clerc committed
825
		delete_hist_label=g_strdup_printf(_("Delete chat history of '%s'"),name);
aymeric's avatar
aymeric committed
826
		g_free(name);
827
		show_menu_separator=TRUE;
smorlat's avatar
smorlat committed
828 829 830
	}
	if (edit_label){
		menu_item=gtk_image_menu_item_new_with_label(edit_label);
831
		image=gtk_image_new_from_icon_name("linphone-edit",GTK_ICON_SIZE_MENU);
smorlat's avatar
smorlat committed
832 833 834 835 836 837 838 839
		gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),image);
		gtk_widget_show(image);
		gtk_widget_show(menu_item);
		gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item);
		g_signal_connect_swapped(G_OBJECT(menu_item),"activate",(GCallback)linphone_gtk_edit_contact,contact_list);
	}
	if (delete_label){
		menu_item=gtk_image_menu_item_new_with_label(delete_label);
840
		image=gtk_image_new_from_icon_name("linphone-delete",GTK_ICON_SIZE_MENU);
smorlat's avatar
smorlat committed
841 842 843 844 845 846
		gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),image);
		gtk_widget_show(image);
		gtk_widget_show(menu_item);
		gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item);
		g_signal_connect_swapped(G_OBJECT(menu_item),"activate",(GCallback)linphone_gtk_remove_contact,contact_list);
	}
847

Margaux Clerc's avatar
Margaux Clerc committed
848
	if (delete_hist_label){
849 850 851
		GtkWidget *menu_item_separator=gtk_separator_menu_item_new();
		gtk_widget_show(menu_item_separator);
		gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item_separator);
Margaux Clerc's avatar
Margaux Clerc committed
852
		menu_item=gtk_image_menu_item_new_with_label(delete_hist_label);
853
		image=gtk_image_new_from_icon_name("linphone-delete",GTK_ICON_SIZE_MENU);
Margaux Clerc's avatar
Margaux Clerc committed
854 855 856 857 858 859
		gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),image);
		gtk_widget_show(image);
		gtk_widget_show(menu_item);
		gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item);
		g_signal_connect_swapped(G_OBJECT(menu_item),"activate",(GCallback)linphone_gtk_delete_history,contact_list);
	}
smorlat's avatar
smorlat committed
860

smorlat's avatar
smorlat committed
861
	if (ssc && (sip_setup_context_get_capabilities(ssc) & SIP_SETUP_CAP_BUDDY_LOOKUP)) {
smorlat's avatar
smorlat committed
862 863 864
		gchar *tmp=g_strdup_printf(_("Add new contact from %s directory"),linphone_proxy_config_get_domain(cfg));
		menu_item=gtk_image_menu_item_new_with_label(tmp);
		g_free(tmp);
865
		image=gtk_image_new_from_icon_name("linphone-contact-add",GTK_ICON_SIZE_MENU);
smorlat's avatar
smorlat committed
866 867 868 869 870 871
		gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),image);
		gtk_widget_show(image);
		gtk_widget_show(menu_item);
		gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item);
		g_signal_connect_swapped(G_OBJECT(menu_item),"activate",(GCallback)linphone_gtk_show_buddy_lookup_window,ssc);
	}
872

873 874 875 876 877 878 879 880 881 882
	if (show_menu_separator) {
		GtkWidget *menu_item_separator=gtk_separator_menu_item_new();
		gtk_widget_show(menu_item_separator);
		gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item_separator);
	}

	menu_item=gtk_image_menu_item_new_with_label(add_contact_label);
	image=gtk_image_new_from_icon_name("linphone-contact-add",GTK_ICON_SIZE_MENU);
	gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),image);
	gtk_widget_show(image);
aymeric's avatar
aymeric committed
883 884 885 886 887
	gtk_widget_show(menu_item);
	gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item);
	g_signal_connect_swapped(G_OBJECT(menu_item),"activate",(GCallback)linphone_gtk_add_contact,contact_list);
	gtk_widget_show(menu);
	gtk_menu_attach_to_widget (GTK_MENU (menu), contact_list, NULL);
smorlat's avatar
smorlat committed
888

889
	g_free(add_contact_label);
smorlat's avatar
smorlat committed
890 891
	if (edit_label) g_free(edit_label);
	if (delete_label) g_free(delete_label);
aymeric's avatar
aymeric committed
892 893 894 895 896
	return menu;
}

gboolean linphone_gtk_popup_contact_menu(GtkWidget *list, GdkEventButton *event){
	GtkWidget *m=linphone_gtk_create_contact_menu(list);
897
	gtk_menu_popup (GTK_MENU (m), NULL, NULL, NULL, NULL,
aymeric's avatar
aymeric committed
898 899 900 901
                  event ? event->button : 0, event ? event->time : gtk_get_current_event_time());
	return TRUE;
}

902 903 904 905 906
static int get_column_index(GtkTreeView *friendlist, const GtkTreeViewColumn *column) {
	GList *columns = gtk_tree_view_get_columns(friendlist);
	int i = g_list_index(columns, column);
	g_list_free(columns);
	return i;
907 908
}

909 910 911
static void select_row(GtkTreeView *treeview, GtkTreePath *path) {
	GtkTreeSelection *selection = gtk_tree_view_get_selection(treeview);
	gtk_tree_selection_select_path(selection, path);
912 913
}

914
gboolean linphone_gtk_contact_list_button_pressed(GtkTreeView *friendlist, GdkEventButton *event){
aymeric's avatar
aymeric committed
915
	/* Ignore double-clicks and triple-clicks */
916
	gboolean ret = FALSE;
917 918 919 920
	int x_bin, y_bin;
	GtkTreePath *path;
	GtkTreeViewColumn *column;
	GtkTreeSelection *selection = gtk_tree_view_get_selection(friendlist);
921

922 923
	gtk_tree_view_convert_widget_to_bin_window_coords(friendlist, event->x, event->y, &x_bin, &y_bin);
	gtk_tree_view_get_path_at_pos(friendlist, x_bin, y_bin, &path, &column, NULL, NULL);
924

925
	if (event->button == 3 && event->type == GDK_BUTTON_PRESS) {
926 927
		if(path) gtk_tree_selection_select_path(selection, path);
		ret = linphone_gtk_popup_contact_menu(GTK_WIDGET(friendlist), event);
928
	} else if(event->button == 1 && event->type == GDK_BUTTON_PRESS){
929 930 931 932
		if(path && column) {
			int numcol = get_column_index(friendlist, column);
			if(numcol == 2) {
				select_row(friendlist, path);
François Grisez's avatar