main.c 40 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
/*
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.
*/

#define USE_LIBGLADE 1

22
#include "linphone.h"
aymeric's avatar
aymeric committed
23 24
#include "lpconfig.h"

25

aymeric's avatar
aymeric committed
26 27 28 29 30 31 32 33 34

#ifdef USE_LIBGLADE
#include <glade/glade.h>
#endif

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

smorlat's avatar
smorlat committed
35
#define LINPHONE_ICON "linphone2.png"
aymeric's avatar
aymeric committed
36

smorlat's avatar
smorlat committed
37 38
const char *this_program_ident_string="linphone_ident_string=" LINPHONE_VERSION;

aymeric's avatar
aymeric committed
39 40 41 42 43 44
static LinphoneCore *the_core=NULL;
static GtkWidget *the_ui=NULL;

static void linphone_gtk_show(LinphoneCore *lc);
static void linphone_gtk_inv_recv(LinphoneCore *lc, const char *from);
static void linphone_gtk_bye_recv(LinphoneCore *lc, const char *from);
45
static void linphone_gtk_notify_recv(LinphoneCore *lc, LinphoneFriend * fid);
aymeric's avatar
aymeric committed
46 47 48 49 50 51 52 53 54
static void linphone_gtk_new_unknown_subscriber(LinphoneCore *lc, LinphoneFriend *lf, const char *url);
static void linphone_gtk_auth_info_requested(LinphoneCore *lc, const char *realm, const char *username);
static void linphone_gtk_display_status(LinphoneCore *lc, const char *status);
static void linphone_gtk_display_message(LinphoneCore *lc, const char *msg);
static void linphone_gtk_display_warning(LinphoneCore *lc, const char *warning);
static void linphone_gtk_display_url(LinphoneCore *lc, const char *msg, const char *url);
static void linphone_gtk_display_question(LinphoneCore *lc, const char *question);
static void linphone_gtk_call_log_updated(LinphoneCore *lc, LinphoneCallLog *cl);
static void linphone_gtk_general_state(LinphoneCore *lc, LinphoneGeneralState *gstate);
55 56
static void linphone_gtk_refer_received(LinphoneCore *lc, const char *refer_to);
static gboolean linphone_gtk_auto_answer(GtkWidget *incall_window);
aymeric's avatar
aymeric committed
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71

static LinphoneCoreVTable vtable={
	.show=linphone_gtk_show,
	.inv_recv=linphone_gtk_inv_recv,
	.bye_recv=linphone_gtk_bye_recv,
	.notify_recv=linphone_gtk_notify_recv,
	.new_unknown_subscriber=linphone_gtk_new_unknown_subscriber,
	.auth_info_requested=linphone_gtk_auth_info_requested,
	.display_status=linphone_gtk_display_status,
	.display_message=linphone_gtk_display_message,
	.display_warning=linphone_gtk_display_warning,
	.display_url=linphone_gtk_display_url,
	.display_question=linphone_gtk_display_question,
	.call_log_updated=linphone_gtk_call_log_updated,
	.text_received=linphone_gtk_text_received,
72
	.general_state=linphone_gtk_general_state,
73 74
	.refer_received=linphone_gtk_refer_received,
	.buddy_info_updated=linphone_gtk_buddy_info_updated
aymeric's avatar
aymeric committed
75 76 77
};

static gboolean verbose=0;
78 79
static gboolean auto_answer = 0;
static gchar * addr_to_call = NULL;
smorlat's avatar
smorlat committed
80
static gboolean iconified=FALSE;
81 82 83
#ifdef WIN32
static gchar *workingdir=NULL;
#endif
smorlat's avatar
smorlat committed
84

85
static GOptionEntry linphone_options[]={
aymeric's avatar
aymeric committed
86 87 88 89 90
	{
		.long_name="verbose",
		.short_name= '\0',
		.arg=G_OPTION_ARG_NONE,
		.arg_data= (gpointer)&verbose,
91
		.description=N_("log to stdout some debug information while running.")
92
	},
smorlat's avatar
smorlat committed
93 94 95 96 97 98 99
	{
		.long_name="iconified",
		.short_name= '\0',
		.arg=G_OPTION_ARG_NONE,
		.arg_data= (gpointer)&iconified,
		.description=N_("Start only in the system tray, do not show the main interface.")
	},
100
	{
101 102 103
	    .long_name = "call",
	    .short_name = 'c',
	    .arg = G_OPTION_ARG_STRING,
104 105
	    .arg_data = &addr_to_call,
	    .description = N_("address to call right now")
106
	},
107
	{
108 109 110 111
	    .long_name = "auto-answer",
	    .short_name = 'a',
	    .arg = G_OPTION_ARG_NONE,
	    .arg_data = (gpointer) & auto_answer,
112
	    .description = N_("if set automatically answer incoming calls")
113
	},
114 115 116 117 118 119 120 121 122
#ifdef WIN32
	{				/* zsd addition */
	    .long_name = "workdir",
	    .short_name = '\0',
	    .arg = G_OPTION_ARG_STRING,
	    .arg_data = (gpointer) & workingdir,
	    .description = N_("Specifiy a working directory (should be the base of the installation, eg: c:\\Program Files\\Linphone)")
	},
#endif
123
	{0}
aymeric's avatar
aymeric committed
124 125 126 127
};

#define INSTALLED_XML_DIR PACKAGE_DATA_DIR "/linphone"
#define BUILD_TREE_XML_DIR "gtk-glade"
smorlat's avatar
smorlat committed
128 129

#ifndef WIN32
aymeric's avatar
aymeric committed
130
#define CONFIG_FILE ".linphonerc"
smorlat's avatar
smorlat committed
131 132 133 134 135
#else
#define CONFIG_FILE "linphonerc"
#endif


aymeric's avatar
aymeric committed
136

smorlat's avatar
smorlat committed
137 138
static char _config_file[1024];

smorlat's avatar
smorlat committed
139

smorlat's avatar
smorlat committed
140
const char *linphone_gtk_get_config_file(){
aymeric's avatar
aymeric committed
141 142
	/*try accessing a local file first if exists*/
	if (access(CONFIG_FILE,F_OK)==0){
smorlat's avatar
smorlat committed
143
		snprintf(_config_file,sizeof(_config_file),"%s",CONFIG_FILE);
aymeric's avatar
aymeric committed
144 145 146 147
	}else{
#ifdef WIN32
		const char *appdata=getenv("APPDATA");
		if (appdata){
smorlat's avatar
smorlat committed
148
			snprintf(_config_file,sizeof(_config_file),"%s\\%s",appdata,LINPHONE_CONFIG_DIR);
smorlat's avatar
smorlat committed
149
			CreateDirectory(_config_file,NULL);
smorlat's avatar
smorlat committed
150
			snprintf(_config_file,sizeof(_config_file),"%s\\%s",appdata,LINPHONE_CONFIG_DIR "\\" CONFIG_FILE);
aymeric's avatar
aymeric committed
151 152
		}
#else
153 154
		const char *home=getenv("HOME");
		if (home==NULL) home=".";
smorlat's avatar
smorlat committed
155
		snprintf(_config_file,sizeof(_config_file),"%s/%s",home,CONFIG_FILE);
aymeric's avatar
aymeric committed
156 157
#endif
	}
smorlat's avatar
smorlat committed
158 159 160 161
	return _config_file;
}

static void linphone_gtk_init_liblinphone(const char *file){
smorlat's avatar
smorlat committed
162
	linphone_core_set_user_agent("Linphone", LINPHONE_VERSION);
163
	the_core=linphone_core_new(&vtable,file,NULL,NULL);
164
	linphone_core_set_waiting_callback(the_core,linphone_gtk_wait,NULL);
aymeric's avatar
aymeric committed
165 166 167 168 169 170 171 172 173 174 175 176
}



LinphoneCore *linphone_gtk_get_core(void){
	return the_core;
}

GtkWidget *linphone_gtk_get_main_window(){
	return the_ui;
}

smorlat's avatar
smorlat committed
177
static void parse_item(const char *item, const char *window_name, GtkWidget *w,  gboolean show){
smorlat's avatar
smorlat committed
178 179 180 181 182 183 184 185 186
	char tmp[64];
	char *dot;
	strcpy(tmp,item);
	dot=strchr(tmp,'.');
	if (dot){
		*dot='\0';
		dot++;
		if (strcmp(window_name,tmp)==0){
			GtkWidget *wd=linphone_gtk_get_widget(w,dot);
smorlat's avatar
smorlat committed
187 188 189 190
			if (wd) {
				if (!show) gtk_widget_hide(wd);
				else gtk_widget_show(wd);
			}
smorlat's avatar
smorlat committed
191 192 193 194
		}
	}
}

smorlat's avatar
smorlat committed
195
static void parse_widgets(const char *hiddens, const char *window_name, GtkWidget *w, gboolean show){
smorlat's avatar
smorlat committed
196 197 198 199 200 201 202 203 204 205
	char item[64];
	const char *i;
	const char *b;
	int len;
	for(b=i=hiddens;*i!='\0';++i){
		if (*i==' '){
			len=MIN(i-b,sizeof(item)-1);
			strncpy(item,b,len);
			item[len]='\0';
			b=i+1;
smorlat's avatar
smorlat committed
206
			parse_item(item,window_name,w,show);
smorlat's avatar
smorlat committed
207 208 209 210 211 212
		}
	}
	len=MIN(i-b,sizeof(item)-1);
	if (len>0){
		strncpy(item,b,len);
		item[len]='\0';
smorlat's avatar
smorlat committed
213
		parse_item(item,window_name,w,show);
smorlat's avatar
smorlat committed
214 215 216 217
	}
}

static void linphone_gtk_configure_window(GtkWidget *w, const char *window_name){
smorlat's avatar
smorlat committed
218 219 220
	static const char *icon_path=NULL;
	static const char *hiddens=NULL;
	static const char *shown=NULL;
221
	static bool_t config_loaded=FALSE;
smorlat's avatar
smorlat committed
222
	if (linphone_gtk_get_core()==NULL) return;
223 224
	if (config_loaded==FALSE){
		hiddens=linphone_gtk_get_ui_config("hidden_widgets",NULL);
smorlat's avatar
smorlat committed
225
		shown=linphone_gtk_get_ui_config("shown_widgets",NULL);
226 227 228
		icon_path=linphone_gtk_get_ui_config("icon",NULL);
		config_loaded=TRUE;
	}
smorlat's avatar
smorlat committed
229 230 231 232
	if (hiddens)
		parse_widgets(hiddens,window_name,w,FALSE);
	if (shown)
		parse_widgets(shown,window_name,w,TRUE);
233 234 235 236 237
	if (icon_path) {
		GdkPixbuf *pbuf=create_pixbuf(icon_path);
		gtk_window_set_icon(GTK_WINDOW(w),pbuf);
		g_object_unref(G_OBJECT(pbuf));
	}
smorlat's avatar
smorlat committed
238 239
}

aymeric's avatar
aymeric committed
240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258
#ifdef USE_LIBGLADE

GtkWidget *linphone_gtk_create_window(const char *window_name){
	GtkWidget *w;
	GladeXML *gxml;
	char path[2048];
	snprintf(path,sizeof(path),"%s/%s.glade",BUILD_TREE_XML_DIR,window_name);
	if (access(path,F_OK)!=0){
		snprintf(path,sizeof(path),"%s/%s.glade",INSTALLED_XML_DIR,window_name);
		if (access(path,F_OK)!=0){
			g_error("Could not locate neither %s/%s.glade and %s/%s.glade .",BUILD_TREE_XML_DIR,window_name,
				INSTALLED_XML_DIR,window_name);
			return NULL;
		}
	}
	gxml=glade_xml_new(path,NULL,NULL);
	glade_xml_signal_autoconnect(gxml);
	w=glade_xml_get_widget(gxml,window_name);
	if (w==NULL) g_error("Could not retrieve '%s' window from xml file",window_name);
smorlat's avatar
smorlat committed
259
	linphone_gtk_configure_window(w,window_name);
aymeric's avatar
aymeric committed
260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300
	return w;
}

GtkWidget *linphone_gtk_get_widget(GtkWidget *window, const char *name){
	GtkWidget *w;
	GladeXML *gxml=glade_get_widget_tree(window);
	if (gxml==NULL) g_error("Could not retrieve XML tree of window %s",name);
	w=glade_xml_get_widget(gxml,name);
	if (w==NULL) g_error("Could not retrieve widget %s",name);
	return GTK_WIDGET(w);
}

#else

GtkWidget *linphone_gtk_create_window(const char *window_name){
	
}

GtkWidget *linphone_gtk_get_widget(GtkWidget *window, const char *name){
	GObject *w=gtk_builder_get_object(the_ui,name);
	if (w==NULL){
		g_error("No widget named %s found in xml interface.",name);
	}
	return GTK_WIDGET(w);
}

#endif

void linphone_gtk_display_something(GtkMessageType type,const gchar *message){
	GtkWidget *dialog;
	GtkWidget *main_window=linphone_gtk_get_main_window();
	
	gtk_widget_show(main_window);
	if (type==GTK_MESSAGE_QUESTION)
	{
		/* draw a question box. link to dialog_click callback */
		dialog = gtk_message_dialog_new (
				GTK_WINDOW(main_window),
                                GTK_DIALOG_DESTROY_WITH_PARENT,
				GTK_MESSAGE_QUESTION,
                                GTK_BUTTONS_YES_NO,
smorlat's avatar
smorlat committed
301
                                "%s",
aymeric's avatar
aymeric committed
302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317
				(const gchar*)message);
		/* connect to some callback : REVISIT */
		/*
		g_signal_connect_swapped (G_OBJECT (dialog), "response",
                           G_CALLBACK (dialog_click),
                           G_OBJECT (dialog));
		*/
		/* actually show the box */
		gtk_widget_show(dialog);
	}
	else
	{
		dialog = gtk_message_dialog_new (GTK_WINDOW(main_window),
                                  GTK_DIALOG_DESTROY_WITH_PARENT,
                                  type,
                                  GTK_BUTTONS_CLOSE,
smorlat's avatar
smorlat committed
318
                                  "%s",
aymeric's avatar
aymeric committed
319 320 321 322 323 324 325 326 327 328 329 330 331 332 333
                                  (const gchar*)message);
		/* Destroy the dialog when the user responds to it (e.g. clicks a button) */
		g_signal_connect_swapped (G_OBJECT (dialog), "response",
                           G_CALLBACK (gtk_widget_destroy),
                           G_OBJECT (dialog));
		gtk_widget_show(dialog);
	}
}

void linphone_gtk_about_response(GtkDialog *dialog, gint id){
	if (id==GTK_RESPONSE_CANCEL){
		gtk_widget_destroy(GTK_WIDGET(dialog));
	}
}

334 335 336 337 338
static void about_url_clicked(GtkAboutDialog *dialog, const char *url, gpointer data){
	g_message("About url clicked");
	linphone_gtk_open_browser(url);
}

aymeric's avatar
aymeric committed
339 340
void linphone_gtk_show_about(){
	struct stat filestat;
341
	const char *license_file=PACKAGE_DATA_DIR "/linphone/COPYING";
aymeric's avatar
aymeric committed
342
	GtkWidget *about;
343
	
aymeric's avatar
aymeric committed
344
	about=linphone_gtk_create_window("about");
345
	gtk_about_dialog_set_url_hook(about_url_clicked,NULL,NULL);
aymeric's avatar
aymeric committed
346 347 348 349 350 351 352 353 354 355 356 357 358 359 360
	memset(&filestat,0,sizeof(filestat));
	if (stat(license_file,&filestat)!=0){
		license_file="COPYING";
		stat(license_file,&filestat);
	}
	if (filestat.st_size>0){
		char *license=g_malloc(filestat.st_size+1);
		FILE *f=fopen(license_file,"r");
		if (f && fread(license,filestat.st_size,1,f)==1){
			license[filestat.st_size]='\0';
			gtk_about_dialog_set_license(GTK_ABOUT_DIALOG(about),license);
		}
		g_free(license);
	}
	gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(about),LINPHONE_VERSION);
361 362
	gtk_about_dialog_set_program_name(GTK_ABOUT_DIALOG(about),linphone_gtk_get_ui_config("title","Linphone"));
	gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(about),linphone_gtk_get_ui_config("home","http://www.linphone.org"));
aymeric's avatar
aymeric committed
363 364 365
	gtk_widget_show(about);
}

366 367 368 369 370
static void set_video_window_decorations(GdkWindow *w){
	const char *title=linphone_gtk_get_ui_config("title","Linphone");
	const char *icon_path=linphone_gtk_get_ui_config("icon","linphone2.png");
	char video_title[256];
	GdkPixbuf *pbuf=create_pixbuf(icon_path);
smorlat's avatar
smorlat committed
371
	if (!linphone_core_in_call(linphone_gtk_get_core())){
372 373 374
		snprintf(video_title,sizeof(video_title),"%s video",title);
		/* When not in call, treat the video as a normal window */
		gdk_window_set_keep_above(w, FALSE);
smorlat's avatar
smorlat committed
375
	}else{
376 377
		LinphoneAddress *uri =
			linphone_address_clone(linphone_core_get_remote_uri(linphone_gtk_get_core()));
378
		char *display_name;
379 380 381

		linphone_address_clean(uri);
		if (linphone_address_get_display_name(uri)!=NULL){
382
			display_name=ms_strdup(linphone_address_get_display_name(uri));
383
		}else{
384
			display_name=linphone_address_as_string(uri);
385 386
		}
		snprintf(video_title,sizeof(video_title),_("Call with %s"),display_name);
387
		linphone_address_destroy(uri);
388
		ms_free(display_name);
389 390 391 392 393 394 395 396

		/* During calls, bring up the video window, arrange so that
		it is above all the other windows */
		gdk_window_deiconify(w);
		gdk_window_set_keep_above(w,TRUE);
		/* Maybe we should have the following, but then we want to
		have a timer that turns it off after a little while. */
		/* gdk_window_set_urgency_hint(w,TRUE); */
smorlat's avatar
smorlat committed
397
	}
398
	gdk_window_set_title(w,video_title);
399 400 401 402
	/* Refrain the video window to be closed at all times. */
	gdk_window_set_functions(w,
				 GDK_FUNC_RESIZE|GDK_FUNC_MOVE|
				 GDK_FUNC_MINIMIZE|GDK_FUNC_MAXIMIZE);
403 404 405 406 407 408 409 410 411
	if (pbuf){
		GList *l=NULL;
		l=g_list_append(l,pbuf);
		gdk_window_set_icon_list(w,l);
		g_list_free(l);
		g_object_unref(G_OBJECT(pbuf));
	}
}

smorlat's avatar
smorlat committed
412 413 414 415 416
static gboolean video_needs_update=FALSE;

static void update_video_title(){
	video_needs_update=TRUE;
}
417

aymeric's avatar
aymeric committed
418
static gboolean linphone_gtk_iterate(LinphoneCore *lc){
419
	static gboolean first_time=TRUE;
420 421
	unsigned long id;
	static unsigned long previd=0;
smorlat's avatar
smorlat committed
422 423 424 425 426
	static gboolean in_iterate=FALSE;
	
	/*avoid reentrancy*/
	if (in_iterate) return TRUE;
	in_iterate=TRUE;
aymeric's avatar
aymeric committed
427
	linphone_core_iterate(lc);
428 429 430 431 432 433
	if (first_time){
		/*after the first call to iterate, SipSetupContexts should be ready, so take actions:*/
		linphone_gtk_show_directory_search();
		first_time=FALSE;
	}

434
	id=linphone_core_get_native_video_window_id(lc);
smorlat's avatar
smorlat committed
435
	if (id!=previd || video_needs_update){
436 437 438
		GdkWindow *w;
		previd=id;
		if (id!=0){
smorlat's avatar
smorlat committed
439
			ms_message("Updating window decorations");
440
#ifndef WIN32
441
			w=gdk_window_foreign_new(id);
442 443 444
#else
			w=gdk_window_foreign_new((HANDLE)id);
#endif
445 446 447 448 449
			if (w) {
				set_video_window_decorations(w);
				g_object_unref(G_OBJECT(w));
			}
			else ms_error("gdk_window_foreign_new() failed");
smorlat's avatar
smorlat committed
450
			if (video_needs_update) video_needs_update=FALSE;
451 452
		}
	}
453
	if (addr_to_call!=NULL){
smorlat's avatar
smorlat committed
454 455 456 457 458 459 460 461 462
		/*make sure we are not showing the login screen*/
		GtkWidget *mw=linphone_gtk_get_main_window();
		GtkWidget *login_frame=linphone_gtk_get_widget(mw,"login_frame");
		if (!GTK_WIDGET_VISIBLE(login_frame)){
			GtkWidget *uri_bar=linphone_gtk_get_widget(mw,"uribar");
			gtk_entry_set_text(GTK_ENTRY(uri_bar),addr_to_call);
			addr_to_call=NULL;
			linphone_gtk_start_call(uri_bar);
		}
463
	}
smorlat's avatar
smorlat committed
464
	in_iterate=FALSE;
aymeric's avatar
aymeric committed
465 466 467 468 469 470 471 472 473 474 475 476
	return TRUE;
}

static void load_uri_history(){
	GtkEntry *uribar=GTK_ENTRY(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"uribar"));
	char key[20];
	int i;
	GtkEntryCompletion *gep=gtk_entry_completion_new();
	GtkListStore *model=gtk_list_store_new(1,G_TYPE_STRING);
	for (i=0;;i++){
		const char *uri;
		snprintf(key,sizeof(key),"uri%i",i);
477
		uri=linphone_gtk_get_ui_config(key,NULL);
aymeric's avatar
aymeric committed
478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539
		if (uri!=NULL) {
			GtkTreeIter iter;
			gtk_list_store_append(model,&iter);
			gtk_list_store_set(model,&iter,0,uri,-1);
			if (i==0) gtk_entry_set_text(uribar,uri);
		}
		else break;
	}
	gtk_entry_completion_set_model(gep,GTK_TREE_MODEL(model));
	gtk_entry_completion_set_text_column(gep,0);
	gtk_entry_set_completion(uribar,gep);
}

static void save_uri_history(){
	LinphoneCore *lc=linphone_gtk_get_core();
	LpConfig *cfg=linphone_core_get_config(lc);
	GtkEntry *uribar=GTK_ENTRY(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"uribar"));
	char key[20];
	int i=0;
	char *uri=NULL;
	GtkTreeIter iter;
	GtkTreeModel *model=gtk_entry_completion_get_model(gtk_entry_get_completion(uribar));

	if (!gtk_tree_model_get_iter_first(model,&iter)) return;
	do {
		gtk_tree_model_get(model,&iter,0,&uri,-1);
		if (uri) {
			snprintf(key,sizeof(key),"uri%i",i);
			lp_config_set_string(cfg,"GtkUi",key,uri);
			g_free(uri);
		}else break;
		i++;
		if (i>5) break;
	}while(gtk_tree_model_iter_next(model,&iter));
	lp_config_sync(cfg);
}

static void completion_add_text(GtkEntry *entry, const char *text){
	GtkTreeIter iter;
	GtkTreeModel *model=gtk_entry_completion_get_model(gtk_entry_get_completion(entry));
	
	if (gtk_tree_model_get_iter_first(model,&iter)){ 
		do {
			gchar *uri=NULL;
			gtk_tree_model_get(model,&iter,0,&uri,-1);
			if (uri!=NULL){
				if (strcmp(uri,text)==0) {
					/*remove text */
					gtk_list_store_remove(GTK_LIST_STORE(model),&iter);
					g_free(uri);
					break;
				}
				g_free(uri);
			}
		}while (gtk_tree_model_iter_next(model,&iter));
	}
	/* and prepend it on top of the list */
	gtk_list_store_prepend(GTK_LIST_STORE(model),&iter);
	gtk_list_store_set(GTK_LIST_STORE(model),&iter,0,text,-1);
	save_uri_history();
}

smorlat's avatar
smorlat committed
540 541
void linphone_gtk_call_terminated(const char *error){
	GtkWidget *mw=linphone_gtk_get_main_window();
542
	GtkWidget *icw;
543 544
	gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"terminate_call"),FALSE);
	gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"start_call"),TRUE);
smorlat's avatar
smorlat committed
545
	gtk_widget_hide_all(linphone_gtk_get_widget(mw,"go_to_call_view_box"));
smorlat's avatar
smorlat committed
546
	linphone_gtk_enable_mute_button(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(mw,"main_mute")),FALSE);
smorlat's avatar
smorlat committed
547 548
	if (linphone_gtk_use_in_call_view())
		linphone_gtk_in_call_view_terminate(error);
smorlat's avatar
smorlat committed
549
	update_video_title();
550 551 552 553 554
	icw=GTK_WIDGET(g_object_get_data(G_OBJECT(mw),"incoming_call"));
	if (icw!=NULL){
		g_object_set_data(G_OBJECT(mw),"incoming_call",NULL);
		gtk_widget_destroy(icw);
	}
smorlat's avatar
smorlat committed
555 556
}

smorlat's avatar
smorlat committed
557 558 559 560 561
static gboolean in_call_timer(){
	if (linphone_core_in_call(linphone_gtk_get_core())){
		linphone_gtk_in_call_view_update_duration(
			linphone_core_get_current_call_duration(linphone_gtk_get_core()));
		return TRUE;
smorlat's avatar
smorlat committed
562
	}
smorlat's avatar
smorlat committed
563
	return FALSE;
smorlat's avatar
smorlat committed
564 565
}

aymeric's avatar
aymeric committed
566
static void linphone_gtk_call_started(GtkWidget *mw){
567 568
	gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"start_call"),FALSE);
	gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"terminate_call"),TRUE);
smorlat's avatar
smorlat committed
569
	gtk_widget_show_all(linphone_gtk_get_widget(mw,"go_to_call_view_box"));
smorlat's avatar
smorlat committed
570
	update_video_title();
smorlat's avatar
smorlat committed
571 572
	if (linphone_gtk_use_in_call_view())
		g_timeout_add(250,(GSourceFunc)in_call_timer,NULL);
smorlat's avatar
smorlat committed
573 574 575 576 577 578 579 580 581
}

static gboolean linphone_gtk_start_call_do(GtkWidget *uri_bar){
	const char *entered=gtk_entry_get_text(GTK_ENTRY(uri_bar));
	if (linphone_core_invite(linphone_gtk_get_core(),entered)==0) {
		completion_add_text(GTK_ENTRY(uri_bar),entered);
	}else{
	}
	return FALSE;
aymeric's avatar
aymeric committed
582 583
}

smorlat's avatar
smorlat committed
584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603
static void _linphone_gtk_accept_call(){
	LinphoneCore *lc=linphone_gtk_get_core();
	GtkWidget *mw=linphone_gtk_get_main_window();
	GtkWidget *icw=GTK_WIDGET(g_object_get_data(G_OBJECT(mw),"incoming_call"));
	if (icw!=NULL){
		g_object_set_data(G_OBJECT(mw),"incoming_call",NULL);
		gtk_widget_destroy(icw);
	}

	linphone_core_accept_call(lc,NULL);
	linphone_gtk_call_started(linphone_gtk_get_main_window());
	if (linphone_gtk_use_in_call_view()){
		linphone_gtk_in_call_view_set_in_call();
		linphone_gtk_show_in_call_view();
	}
	linphone_gtk_enable_mute_button(
		GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"main_mute"))
		,TRUE);
}

smorlat's avatar
smorlat committed
604
void linphone_gtk_start_call(GtkWidget *w){
aymeric's avatar
aymeric committed
605
	LinphoneCore *lc=linphone_gtk_get_core();
smorlat's avatar
smorlat committed
606 607 608 609
	if (linphone_core_inc_invite_pending(lc)){
		/*accept the call*/
		_linphone_gtk_accept_call();
	}else if (linphone_core_in_call(lc)) {
aymeric's avatar
aymeric committed
610 611
		/*already in call */
	}else{
smorlat's avatar
smorlat committed
612 613 614
		/*change into in-call mode, then do the work later as it might block a bit */
		GtkWidget *mw=gtk_widget_get_toplevel(w);
		GtkWidget *uri_bar=linphone_gtk_get_widget(mw,"uribar");
aymeric's avatar
aymeric committed
615
		const char *entered=gtk_entry_get_text(GTK_ENTRY(uri_bar));
smorlat's avatar
smorlat committed
616
		linphone_gtk_call_started(mw);
smorlat's avatar
smorlat committed
617 618 619 620
		if (linphone_gtk_use_in_call_view()){
			linphone_gtk_in_call_view_set_calling(entered);
			linphone_gtk_show_in_call_view();
		}
smorlat's avatar
smorlat committed
621
		g_timeout_add(100,(GSourceFunc)linphone_gtk_start_call_do,uri_bar);
aymeric's avatar
aymeric committed
622 623 624
	}
}

smorlat's avatar
smorlat committed
625 626 627 628 629
void linphone_gtk_uri_bar_activate(GtkWidget *w){
	linphone_gtk_start_call(w);
}


aymeric's avatar
aymeric committed
630 631 632 633 634 635 636 637 638 639
void linphone_gtk_terminate_call(GtkWidget *button){
	linphone_core_terminate_call(linphone_gtk_get_core(),NULL);
}

void linphone_gtk_decline_call(GtkWidget *button){
	linphone_core_terminate_call(linphone_gtk_get_core(),NULL);
	gtk_widget_destroy(gtk_widget_get_toplevel(button));
}

void linphone_gtk_accept_call(GtkWidget *button){
smorlat's avatar
smorlat committed
640
	_linphone_gtk_accept_call();
aymeric's avatar
aymeric committed
641 642
}

643 644 645 646 647
static gboolean linphone_gtk_auto_answer(GtkWidget *incall_window){
	linphone_gtk_accept_call(linphone_gtk_get_widget(incall_window,"accept_call"));
	return FALSE;
}

aymeric's avatar
aymeric committed
648 649
void linphone_gtk_set_audio_video(){
	linphone_core_enable_video(linphone_gtk_get_core(),TRUE,TRUE);
650
	linphone_core_enable_video_preview(linphone_gtk_get_core(),TRUE);
aymeric's avatar
aymeric committed
651 652 653 654
}

void linphone_gtk_set_audio_only(){
	linphone_core_enable_video(linphone_gtk_get_core(),FALSE,FALSE);
655
	linphone_core_enable_video_preview(linphone_gtk_get_core(),FALSE);
aymeric's avatar
aymeric committed
656 657
}

smorlat's avatar
smorlat committed
658 659 660 661 662
void linphone_gtk_enable_self_view(GtkWidget *w){
	linphone_core_enable_self_view(linphone_gtk_get_core(),
		gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w)));
}

aymeric's avatar
aymeric committed
663 664 665
void linphone_gtk_used_identity_changed(GtkWidget *w){
	int active=gtk_combo_box_get_active(GTK_COMBO_BOX(w));
	char *sel=gtk_combo_box_get_active_text(GTK_COMBO_BOX(w));
666
	if (sel && strlen(sel)>0){ //avoid a dummy "changed" at gui startup
aymeric's avatar
aymeric committed
667
		linphone_core_set_default_proxy_index(linphone_gtk_get_core(),(active==0) ? -1 : (active-1));
668 669
		linphone_gtk_show_directory_search();
	}
smorlat's avatar
smorlat committed
670
	if (sel) g_free(sel);
aymeric's avatar
aymeric committed
671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688
}

static void linphone_gtk_show_main_window(){
	GtkWidget *w=linphone_gtk_get_main_window();
	LinphoneCore *lc=linphone_gtk_get_core();
	linphone_core_enable_video_preview(lc,linphone_core_video_enabled(lc));
	gtk_widget_show(w);
	gtk_window_present(GTK_WINDOW(w));
}

static void linphone_gtk_show(LinphoneCore *lc){
	linphone_gtk_show_main_window();
}

static void linphone_gtk_inv_recv(LinphoneCore *lc, const char *from){
	GtkWidget *w=linphone_gtk_create_window("incoming_call");
	GtkWidget *label;
	gchar *msg;
689

690 691
	if (auto_answer){
		g_timeout_add(2000,(GSourceFunc)linphone_gtk_auto_answer,w);
692 693
	}

aymeric's avatar
aymeric committed
694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710
	gtk_window_set_transient_for(GTK_WINDOW(w),GTK_WINDOW(linphone_gtk_get_main_window()));
	gtk_window_set_position(GTK_WINDOW(w),GTK_WIN_POS_CENTER_ON_PARENT);

	label=linphone_gtk_get_widget(w,"message");
	msg=g_strdup_printf(_("Incoming call from %s"),from);
	gtk_label_set_text(GTK_LABEL(label),msg);
	gtk_window_set_title(GTK_WINDOW(w),msg);
	gtk_widget_show(w);
	gtk_window_present(GTK_WINDOW(w));
	/*gtk_window_set_urgency_hint(GTK_WINDOW(w),TRUE);*/
	g_free(msg);
	g_object_set_data(G_OBJECT(linphone_gtk_get_main_window()),"incoming_call",w);
	gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"uribar")),
			from);
}

static void linphone_gtk_bye_recv(LinphoneCore *lc, const char *from){
711
	
aymeric's avatar
aymeric committed
712 713
}

714
static void linphone_gtk_notify_recv(LinphoneCore *lc, LinphoneFriend * fid){
aymeric's avatar
aymeric committed
715 716 717 718 719 720 721 722 723 724 725 726 727 728 729
}

static void linphone_gtk_new_subscriber_response(GtkWidget *dialog, guint response_id, LinphoneFriend *lf){
	switch(response_id){
		case GTK_RESPONSE_YES:
			linphone_gtk_show_contact(lf);
		break;
		default:
			linphone_core_reject_subscriber(linphone_gtk_get_core(),lf);
	}
	gtk_widget_destroy(dialog);
}

static void linphone_gtk_new_unknown_subscriber(LinphoneCore *lc, LinphoneFriend *lf, const char *url){
	GtkWidget *dialog;
smorlat's avatar
smorlat committed
730 731 732 733 734 735

	if (linphone_gtk_get_ui_config_int("subscribe_deny_all",0)){
		linphone_core_reject_subscriber(linphone_gtk_get_core(),lf);
		return;
	}

aymeric's avatar
aymeric committed
736 737 738 739 740 741
	gchar *message=g_strdup_printf(_("%s would like to add you to his contact list.\nWould you allow him to see your presence status or add him to your contact list ?\nIf you answer no, this person will be temporarily blacklisted."),url);
	dialog = gtk_message_dialog_new (
				GTK_WINDOW(linphone_gtk_get_main_window()),
                                GTK_DIALOG_DESTROY_WITH_PARENT,
				GTK_MESSAGE_QUESTION,
                                GTK_BUTTONS_YES_NO,
smorlat's avatar
smorlat committed
742
                                "%s",
aymeric's avatar
aymeric committed
743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794
				message);
	g_free(message);
	g_signal_connect(G_OBJECT (dialog), "response",
		G_CALLBACK (linphone_gtk_new_subscriber_response),lf);
	/* actually show the box */
	gtk_widget_show(dialog);
}

typedef struct _AuthTimeout{
	GtkWidget *w;
} AuthTimeout;


static void auth_timeout_clean(AuthTimeout *tout){
	tout->w=NULL;
}

static gboolean auth_timeout_destroy(AuthTimeout *tout){
	if (tout->w)  {
		g_object_weak_unref(G_OBJECT(tout->w),(GWeakNotify)auth_timeout_clean,tout);
		gtk_widget_destroy(tout->w);
	}
	g_free(tout);
	return FALSE;
}

static AuthTimeout * auth_timeout_new(GtkWidget *w){
	AuthTimeout *tout=g_new(AuthTimeout,1);
	tout->w=w;
	/*so that the timeout no more references the widget when it is destroyed:*/
	g_object_weak_ref(G_OBJECT(w),(GWeakNotify)auth_timeout_clean,tout);
	/*so that the widget is automatically destroyed after some time */
	g_timeout_add(30000,(GtkFunction)auth_timeout_destroy,tout);
	return tout;
}

void linphone_gtk_password_cancel(GtkWidget *w){
	LinphoneAuthInfo *info;
	GtkWidget *window=gtk_widget_get_toplevel(w);
	info=(LinphoneAuthInfo*)g_object_get_data(G_OBJECT(window),"auth_info");
	linphone_core_abort_authentication(linphone_gtk_get_core(),info);
	gtk_widget_destroy(window);
}

void linphone_gtk_password_ok(GtkWidget *w){
	GtkWidget *entry;
	GtkWidget *window=gtk_widget_get_toplevel(w);
	LinphoneAuthInfo *info;
	info=(LinphoneAuthInfo*)g_object_get_data(G_OBJECT(window),"auth_info");
	g_object_weak_unref(G_OBJECT(window),(GWeakNotify)linphone_auth_info_destroy,info);
	entry=linphone_gtk_get_widget(window,"password_entry");
	linphone_auth_info_set_passwd(info,gtk_entry_get_text(GTK_ENTRY(entry)));
795 796
	linphone_auth_info_set_userid(info,
		gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(window,"userid_entry"))));
aymeric's avatar
aymeric committed
797 798 799 800 801 802 803 804 805
	linphone_core_add_auth_info(linphone_gtk_get_core(),info);
	gtk_widget_destroy(window);
}

static void linphone_gtk_auth_info_requested(LinphoneCore *lc, const char *realm, const char *username){
	GtkWidget *w=linphone_gtk_create_window("password");
	GtkWidget *label=linphone_gtk_get_widget(w,"message");
	LinphoneAuthInfo *info;
	gchar *msg;
806 807 808 809 810 811 812 813
	GtkWidget *mw=linphone_gtk_get_main_window();
	
	if (mw && GTK_WIDGET_VISIBLE(linphone_gtk_get_widget(mw,"login_frame"))){
		/*don't prompt for authentication when login frame is visible*/
		linphone_core_abort_authentication(lc,NULL);
		return;
	}

814 815 816
	msg=g_strdup_printf(_("Please enter your password for username <i>%s</i>\n at domain <i>%s</i>:"),
		username,realm);
	gtk_label_set_markup(GTK_LABEL(label),msg);
aymeric's avatar
aymeric committed
817
	g_free(msg);
818
	gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(w,"userid_entry")),username);
aymeric's avatar
aymeric committed
819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857
	info=linphone_auth_info_new(username, NULL, NULL, NULL,realm);
	g_object_set_data(G_OBJECT(w),"auth_info",info);
	g_object_weak_ref(G_OBJECT(w),(GWeakNotify)linphone_auth_info_destroy,info);
	gtk_widget_show(w);
	auth_timeout_new(w);
}

static void linphone_gtk_display_status(LinphoneCore *lc, const char *status){
	GtkWidget *w=linphone_gtk_get_main_window();
	GtkWidget *status_bar=linphone_gtk_get_widget(w,"status_bar");
	gtk_statusbar_push(GTK_STATUSBAR(status_bar),
			gtk_statusbar_get_context_id(GTK_STATUSBAR(status_bar),""),
			status);
}

static void linphone_gtk_display_message(LinphoneCore *lc, const char *msg){
	linphone_gtk_display_something(GTK_MESSAGE_INFO,msg);
}

static void linphone_gtk_display_warning(LinphoneCore *lc, const char *warning){
	linphone_gtk_display_something(GTK_MESSAGE_WARNING,warning);
}

static void linphone_gtk_display_url(LinphoneCore *lc, const char *msg, const char *url){
	char richtext[4096];
	snprintf(richtext,sizeof(richtext),"%s %s",msg,url);
	linphone_gtk_display_something(GTK_MESSAGE_INFO,richtext);
}

static void linphone_gtk_display_question(LinphoneCore *lc, const char *question){
	linphone_gtk_display_something(GTK_MESSAGE_QUESTION,question);
}

static void linphone_gtk_call_log_updated(LinphoneCore *lc, LinphoneCallLog *cl){
	GtkWidget *w=(GtkWidget*)g_object_get_data(G_OBJECT(linphone_gtk_get_main_window()),"call_logs");
	if (w) linphone_gtk_call_log_update(w);
}

static void linphone_gtk_general_state(LinphoneCore *lc, LinphoneGeneralState *gstate){
smorlat's avatar
smorlat committed
858 859 860
	switch(gstate->new_state){
		case GSTATE_CALL_OUT_CONNECTED:
		case GSTATE_CALL_IN_CONNECTED:
smorlat's avatar
smorlat committed
861 862
			if (linphone_gtk_use_in_call_view())
				linphone_gtk_in_call_view_set_in_call();
smorlat's avatar
smorlat committed
863 864 865
			linphone_gtk_enable_mute_button(
				GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"main_mute")),
			TRUE);
smorlat's avatar
smorlat committed
866 867 868 869 870 871 872 873 874 875
		break;
		case GSTATE_CALL_ERROR:
			linphone_gtk_call_terminated(gstate->message);
		break;
		case GSTATE_CALL_END:
			linphone_gtk_call_terminated(NULL);
		break;
		default:
		break;
	}
aymeric's avatar
aymeric committed
876 877 878 879 880 881 882
}

static void icon_popup_menu(GtkStatusIcon *status_icon, guint button, guint activate_time, gpointer user_data){
	GtkWidget *menu=(GtkWidget*)g_object_get_data(G_OBJECT(status_icon),"menu");
	gtk_menu_popup(GTK_MENU(menu),NULL,NULL,gtk_status_icon_position_menu,status_icon,button,activate_time);
}

smorlat's avatar
smorlat committed
883
void linphone_gtk_open_browser(const char *url){
smorlat's avatar
smorlat committed
884
	/*in gtk 2.16, gtk_show_uri does not work...*/
885 886 887
#ifndef WIN32
#if GTK_CHECK_VERSION(2,18,3)
	gtk_show_uri(NULL,url,GDK_CURRENT_TIME,NULL);
888
#else
smorlat's avatar
smorlat committed
889
	char cl[255];
smorlat's avatar
smorlat committed
890
	snprintf(cl,sizeof(cl),"/usr/bin/x-www-browser %s",url);
smorlat's avatar
smorlat committed
891
	g_spawn_command_line_async(cl,NULL);
892
#endif
893 894 895
#else /*WIN32*/
	ShellExecute(0,"open",url,NULL,NULL,1);
#endif
896 897
}

smorlat's avatar
smorlat committed
898 899 900 901 902
void linphone_gtk_link_to_website(GtkWidget *item){
	const gchar *home=(const gchar*)g_object_get_data(G_OBJECT(item),"home");
	linphone_gtk_open_browser(home);
}

aymeric's avatar
aymeric committed
903 904 905
static GtkWidget *create_icon_menu(){
	GtkWidget *menu=gtk_menu_new();
	GtkWidget *menu_item;
906
	GtkWidget *image;
smorlat's avatar
smorlat committed
907 908
	gchar *tmp;
	const gchar *homesite;
909
	
smorlat's avatar
smorlat committed
910
	homesite=linphone_gtk_get_ui_config("home","http://www.linphone.org");
smorlat's avatar
smorlat committed
911
	menu_item=gtk_image_menu_item_new_with_label(_("Website link"));
smorlat's avatar
smorlat committed
912 913 914 915
	tmp=g_strdup(homesite);
	g_object_set_data(G_OBJECT(menu_item),"home",tmp);
	g_object_weak_ref(G_OBJECT(menu_item),(GWeakNotify)g_free,tmp);
	
916 917 918 919 920 921 922 923
	image=gtk_image_new_from_stock(GTK_STOCK_HELP,GTK_ICON_SIZE_MENU);
	gtk_widget_show(image);
	gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),image);
	//g_object_unref(G_OBJECT(image));
	gtk_widget_show(menu_item);
	gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item);
	g_signal_connect(G_OBJECT(menu_item),"activate",(GCallback)linphone_gtk_link_to_website,NULL);
	
aymeric's avatar
aymeric committed
924 925 926 927 928 929 930 931 932 933 934 935
	menu_item=gtk_image_menu_item_new_from_stock(GTK_STOCK_ABOUT,NULL);
	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_about,NULL);
	menu_item=gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT,NULL);
	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)gtk_main_quit,NULL);
	gtk_widget_show(menu);
	return menu;
}

smorlat's avatar
smorlat committed
936 937
static GtkStatusIcon *icon=NULL;

aymeric's avatar
aymeric committed
938
static void linphone_gtk_init_status_icon(){
smorlat's avatar
smorlat committed
939 940
	const char *icon_path=linphone_gtk_get_ui_config("icon",LINPHONE_ICON);
	GdkPixbuf *pbuf=create_pixbuf(icon_path);
aymeric's avatar
aymeric committed
941
	GtkWidget *menu=create_icon_menu();
smorlat's avatar
smorlat committed
942
	const char *title;
aymeric's avatar
aymeric committed
943 944 945 946
	icon=gtk_status_icon_new_from_pixbuf(pbuf);
	g_object_unref(G_OBJECT(pbuf));
	g_signal_connect_swapped(G_OBJECT(icon),"activate",(GCallback)linphone_gtk_show_main_window,linphone_gtk_get_main_window());
	g_signal_connect(G_OBJECT(icon),"popup-menu",(GCallback)icon_popup_menu,NULL);
smorlat's avatar
smorlat committed
947 948
	title=linphone_gtk_get_ui_config("title",_("Linphone - a video internet phone"));
	gtk_status_icon_set_tooltip(icon,title);
949
	gtk_status_icon_set_visible(icon,TRUE);
aymeric's avatar
aymeric committed
950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982
	g_object_set_data(G_OBJECT(icon),"menu",menu);
	g_object_weak_ref(G_OBJECT(icon),(GWeakNotify)gtk_widget_destroy,menu);
}

void linphone_gtk_load_identities(void){
	const MSList *elem;
	GtkComboBox *box=GTK_COMBO_BOX(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"identities"));
	char *def_identity;
	LinphoneProxyConfig *def=NULL;
	int def_index=0,i;
	GtkListStore *store;

	store=GTK_LIST_STORE(gtk_combo_box_get_model(box));
	gtk_list_store_clear(store);

	linphone_core_get_default_proxy(linphone_gtk_get_core(),&def);
	def_identity=g_strdup_printf(_("%s (Default)"),linphone_core_get_primary_contact(linphone_gtk_get_core()));
	gtk_combo_box_append_text(box,def_identity);
	g_free(def_identity);
	for(i=1,elem=linphone_core_get_proxy_config_list(linphone_gtk_get_core());
			elem!=NULL;
			elem=ms_list_next(elem),i++){
		LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)elem->data;
		gtk_combo_box_append_text(box,linphone_proxy_config_get_identity(cfg));
		if (cfg==def) {
			def_index=i;
		}
	}
	gtk_combo_box_set_active(box,def_index);
}

static void linphone_gtk_dtmf_clicked(GtkButton *button){
	const char *label=gtk_button_get_label(button);
smorlat's avatar
smorlat committed
983 984 985 986 987 988 989
	if (linphone_core_in_call(linphone_gtk_get_core())){
		linphone_core_send_dtmf(linphone_gtk_get_core(),label[0]);
	}else{
		GtkWidget *uri_bar=linphone_gtk_get_widget(gtk_widget_get_toplevel(GTK_WIDGET(button)),"uribar");
		int pos=-1;
		gtk_editable_insert_text(GTK_EDITABLE(uri_bar),label,1,&pos);
	}
aymeric's avatar
aymeric committed
990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008
}

static void linphone_gtk_connect_digits(void){
	GtkContainer *cont=GTK_CONTAINER(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"dtmf_table"));
	GList *children=gtk_container_get_children(cont);
	GList *elem;
	for(elem=children;elem!=NULL;elem=elem->next){
		GtkButton *button=GTK_BUTTON(elem->data);
		g_signal_connect(G_OBJECT(button),"clicked",(GCallback)linphone_gtk_dtmf_clicked,NULL);
	}
}

static void linphone_gtk_check_menu_items(void){
	bool_t audio_only=!linphone_core_video_enabled(linphone_gtk_get_core());
	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(linphone_gtk_get_widget(
					linphone_gtk_get_main_window(),
					audio_only ? "audio_only_item" : "video_item")), TRUE);
}

smorlat's avatar
smorlat committed
1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020
static gboolean linphone_gtk_can_manage_accounts(){
	LinphoneCore *lc=linphone_gtk_get_core();
	const MSList *elem;
	for(elem=linphone_core_get_sip_setups(lc);elem!=NULL;elem=elem->next){
		SipSetup *ss=(SipSetup*)elem->data;
		if (sip_setup_get_capabilities(ss) & SIP_SETUP_CAP_ACCOUNT_MANAGER){
			return TRUE;
		}
	}
	return FALSE;
}

1021
static void linphone_gtk_configure_main_window(){
smorlat's avatar
smorlat committed
1022 1023 1024
	static gboolean config_loaded=FALSE;
	static const char *title;
	static const char *home;
smorlat's avatar
smorlat committed
1025 1026
	static const char *start_call_icon;
	static const char *stop_call_icon;
smorlat's avatar
smorlat committed
1027
	static gboolean update_check_menu;
1028
	GtkWidget *w=linphone_gtk_get_main_window();
smorlat's avatar
smorlat committed
1029
	if (!config_loaded){
smorlat's avatar
smorlat committed
1030
		title=linphone_gtk_get_ui_config("title","Linphone");
smorlat's avatar
smorlat committed
1031
		home=linphone_gtk_get_ui_config("home","http://www.linphone.org");
1032 1033
		start_call_icon=linphone_gtk_get_ui_config("start_call_icon","green.png");
		stop_call_icon=linphone_gtk_get_ui_config("stop_call_icon","red.png");
smorlat's avatar
smorlat committed
1034
		update_check_menu=linphone_gtk_get_ui_config_int("update_check_menu",0);
smorlat's avatar
smorlat committed
1035
		config_loaded=TRUE;
1036
	}
smorlat's avatar
smorlat committed
1037
	linphone_gtk_configure_window(w,"main_window");
smorlat's avatar
smorlat committed
1038 1039
	if (title) {
		gtk_window_set_title(GTK_WINDOW(w),title);
smorlat's avatar
smorlat committed
1040
#if GTK_CHECK_VERSION(2,16,0)
smorlat's avatar
smorlat committed
1041
		gtk_menu_item_set_label(GTK_MENU_ITEM(linphone_gtk_get_widget(w,"main_menu")),title);
smorlat's avatar
smorlat committed
1042
#endif
smorlat's avatar
smorlat committed
1043
	}
smorlat's avatar
smorlat committed
1044 1045 1046 1047 1048 1049 1050 1051
	if (start_call_icon){
		GdkPixbuf *pbuf=create_pixbuf(start_call_icon);
		gtk_image_set_from_pixbuf(GTK_IMAGE(linphone_gtk_get_widget(w,"start_call_icon")),pbuf);
		g_object_unref(G_OBJECT(pbuf));
	}
	if (stop_call_icon){
		GdkPixbuf *pbuf=create_pixbuf(stop_call_icon);
		gtk_image_set_from_pixbuf(GTK_IMAGE(linphone_gtk_get_widget(w,"terminate_call_icon")),pbuf);
smorlat's avatar
smorlat committed
1052
		gtk_image_set_from_pixbuf(GTK_IMAGE(linphone_gtk_get_widget(w,"in_call_terminate_icon")),pbuf);
smorlat's avatar
smorlat committed
1053 1054
		g_object_unref(G_OBJECT(pbuf));
	}
smorlat's avatar
smorlat committed
1055 1056 1057 1058 1059 1060
	if (home){
		gchar *tmp;
		GtkWidget *menu_item=linphone_gtk_get_widget(w,"home_item");
		tmp=g_strdup(home);
		g_object_set_data(G_OBJECT(menu_item),"home",tmp);
	}
smorlat's avatar
smorlat committed
1061 1062
	if (!linphone_gtk_can_manage_accounts())
		gtk_widget_hide(linphone_gtk_get_widget(w,"run_assistant"));
smorlat's avatar
smorlat committed
1063
	if (update_check_menu){
smorlat's avatar
smorlat committed
1064
		gtk_widget_show(linphone_gtk_get_widget(w,"versioncheck"));
smorlat's avatar
smorlat committed
1065
	}
1066 1067
}

1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079
void linphone_gtk_manage_login(void){
	LinphoneCore *lc=linphone_gtk_get_core();
	LinphoneProxyConfig *cfg=NULL;
	linphone_core_get_default_proxy(lc,&cfg);
	if (cfg){
		SipSetup *ss=linphone_proxy_config_get_sip_setup(cfg);
		if (ss && (sip_setup_get_capabilities(ss) & SIP_SETUP_CAP_LOGIN)){
			linphone_gtk_show_login_frame(cfg);
		}
	}
}

aymeric's avatar
aymeric committed
1080
static void linphone_gtk_init_main_window(){
1081
	linphone_gtk_configure_main_window();
smorlat's avatar
smorlat committed
1082
	linphone_gtk_manage_login();
aymeric's avatar
aymeric committed
1083 1084 1085 1086 1087 1088
	load_uri_history();
	linphone_gtk_load_identities();
	linphone_gtk_set_my_presence(linphone_core_get_presence_info(linphone_gtk_get_core()));
	linphone_gtk_show_friends();
	linphone_gtk_connect_digits();
	linphone_gtk_check_menu_items();
smorlat's avatar
smorlat committed
1089 1090 1091 1092
	linphone_gtk_enable_mute_button(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(linphone_gtk_get_main_window(),
					"main_mute")),FALSE);
	linphone_gtk_enable_mute_button(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(linphone_gtk_get_main_window(),
					"incall_mute")),FALSE);
aymeric's avatar
aymeric committed
1093 1094 1095 1096 1097 1098
	if (linphone_core_in_call(linphone_gtk_get_core())) linphone_gtk_call_started(
		linphone_gtk_get_main_window());/*hide the call button, show terminate button*/
}

void linphone_gtk_close(){
	/* couldn't find a way to prevent closing to destroy the main window*/
smorlat's avatar
smorlat committed
1099
	LinphoneCore *lc=linphone_gtk_get_core();
aymeric's avatar
aymeric committed
1100 1101 1102
	the_ui=NULL;
	the_ui=linphone_gtk_create_window("main");
	linphone_gtk_init_main_window();
smorlat's avatar
??  
smorlat committed
1103 1104 1105
	/*shutdown call if any*/
	if (linphone_core_in_call(lc)){
		linphone_core_terminate_call(lc,NULL);
smorlat's avatar
smorlat committed
1106
		linphone_gtk_call_terminated(NULL);
smorlat's avatar
??  
smorlat committed
1107 1108
	}
	linphone_core_enable_video_preview(lc,FALSE);
aymeric's avatar
aymeric committed
1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149
}

void linphone_gtk_log_handler(OrtpLogLevel lev, const char *fmt, va_list args){
	if (verbose){
		const char *lname="undef";
		char *msg;
		#ifdef __linux
		va_list cap;/*copy of our argument list: a va_list cannot be re-used (SIGSEGV on linux 64 bits)*/
		#endif
		switch(lev){
			case ORTP_DEBUG:
				lname="debug";
				break;
			case ORTP_MESSAGE:
				lname="message";
				break;
			case ORTP_WARNING:
				lname="warning";
				break;
			case ORTP_ERROR:
				lname="error";
				break;
			case ORTP_FATAL:
				lname="fatal";
				break;
			default:
				g_error("Bad level !");
		}
#ifdef __linux
		va_copy(cap,args);
		msg=g_strdup_vprintf(fmt,cap);
		va_end(cap);
#else
		msg=g_strdup_vprintf(fmt,args);
#endif
		fprintf(stdout,"linphone-%s : %s\n",lname,msg);
		ortp_free(msg);
	}
	linphone_gtk_log_push(lev,fmt,args);
}

1150

1151 1152 1153 1154 1155 1156
static void linphone_gtk_refer_received(LinphoneCore *lc, const char *refer_to){
    GtkEntry * uri_bar =GTK_ENTRY(linphone_gtk_get_widget(
		linphone_gtk_get_main_window(), "uribar"));
	linphone_gtk_show_main_window();
	gtk_entry_set_text(uri_bar, refer_to);
	linphone_gtk_start_call(linphone_gtk_get_main_window());
1157 1158
}

aymeric's avatar
aymeric committed
1159
int main(int argc, char *argv[]){
smorlat's avatar
smorlat committed
1160
#ifdef ENABLE_NLS
aymeric's avatar
aymeric committed
1161
	void *p;
smorlat's avatar
smorlat committed
1162
#endif
smorlat's avatar
smorlat committed
1163
	const char *config_file;
1164 1165
	const char *lang;

aymeric's avatar
aymeric committed
1166 1167
	g_thread_init(NULL);
	gdk_threads_init();
1168 1169
	
	config_file=linphone_gtk_get_config_file();
1170

1171 1172 1173 1174 1175 1176 1177 1178 1179 1180
#ifdef WIN32
	/*workaround for windows: sometimes LANG is defined to an integer value, not understood by gtk */
	if ((lang=getenv("LANG"))!=NULL){
		if (atoi(lang)!=0){
			char tmp[128];
			snprintf(tmp,sizeof(tmp),"LANG=",lang);
			_putenv(tmp);
		}
	}
#endif
smorlat's avatar
smorlat committed
1181

1182
	if ((lang=linphone_gtk_get_lang(config_file))!=NULL && lang[0]!='\0'){