]> sjero.net Git - linphone/blobdiff - gtk/main.c
fix warning in gtk app
[linphone] / gtk / main.c
index 6f9c4da6257bbeabeebe5f554f0a378e598f8f5f..1aa2e287c5c2fc6931804ae1608cb48345cb797e 100644 (file)
@@ -18,7 +18,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
 
 
-#define VIDEOSELFVIEW_DEFAULT 1
+#define VIDEOSELFVIEW_DEFAULT 0
 
 #include "linphone.h"
 #include "lpconfig.h"
@@ -36,6 +36,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #define chdir _chdir
 #endif
 
+#if defined(HAVE_NOTIFY1) || defined(HAVE_NOTIFY4)
+#define HAVE_NOTIFY
+#endif
+
 #ifdef HAVE_NOTIFY
 #include <libnotify/notify.h>
 #endif
@@ -48,7 +52,6 @@ static LinphoneCore *the_core=NULL;
 static GtkWidget *the_ui=NULL;
 
 static void linphone_gtk_registration_state_changed(LinphoneCore *lc, LinphoneProxyConfig *cfg, LinphoneRegistrationState rs, const char *msg);
-static void linphone_gtk_show(LinphoneCore *lc);
 static void linphone_gtk_notify_recv(LinphoneCore *lc, LinphoneFriend * fid);
 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);
@@ -58,17 +61,27 @@ 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_call_log_updated(LinphoneCore *lc, LinphoneCallLog *cl);
 static void linphone_gtk_call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cs, const char *msg);
+static void linphone_gtk_call_encryption_changed(LinphoneCore *lc, LinphoneCall *call, bool_t enabled, const char *token);
+static void linphone_gtk_transfer_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate);
+void linphone_gtk_save_main_window_position(GtkWindow* mw, GdkEvent *event, gpointer data);
 static gboolean linphone_gtk_auto_answer(LinphoneCall *call);
-static void linphone_gtk_status_icon_set_blinking(gboolean val);
+void linphone_gtk_status_icon_set_blinking(gboolean val);
+void _linphone_gtk_enable_video(gboolean val);
 
 
+#ifndef HAVE_GTK_OSX
+static gint main_window_x=0;
+static gint main_window_y=0;
+#endif
 static gboolean verbose=0;
 static gboolean auto_answer = 0;
 static gchar * addr_to_call = NULL;
+static gboolean no_video=FALSE;
 static gboolean iconified=FALSE;
 static gchar *workingdir=NULL;
 static char *progpath=NULL;
 gchar *linphone_logfile=NULL;
+static gboolean workaround_gtk_entry_chinese_bug=FALSE;
 
 static GOptionEntry linphone_options[]={
        {
@@ -85,6 +98,13 @@ static GOptionEntry linphone_options[]={
            .arg_data = &linphone_logfile,
            .description = N_("path to a file to write logs into.")
        },
+       {
+           .long_name = "no-video",
+           .short_name = '\0',
+           .arg = G_OPTION_ARG_NONE,
+           .arg_data = (gpointer)&no_video,
+           .description = N_("Start linphone with video disabled.")
+       },
        {
                .long_name="iconified",
                .short_name= '\0',
@@ -117,42 +137,41 @@ static GOptionEntry linphone_options[]={
 };
 
 #define INSTALLED_XML_DIR PACKAGE_DATA_DIR "/linphone"
-#define RELATIVE_XML_DIR 
+#define RELATIVE_XML_DIR
 #define BUILD_TREE_XML_DIR "gtk"
 
 #ifndef WIN32
 #define CONFIG_FILE ".linphonerc"
+#define SECRETS_FILE ".linphone-zidcache"
 #else
 #define CONFIG_FILE "linphonerc"
+#define SECRETS_FILE "linphone-zidcache"
 #endif
 
-
-
-static char _config_file[1024];
-
-
-const char *linphone_gtk_get_config_file(){
+char *linphone_gtk_get_config_file(const char *filename){
+       const int path_max=1024;
+       char *config_file=g_malloc0(path_max);
+       if (filename==NULL) filename=CONFIG_FILE;
        /*try accessing a local file first if exists*/
        if (access(CONFIG_FILE,F_OK)==0){
-               snprintf(_config_file,sizeof(_config_file),"%s",CONFIG_FILE);
+               snprintf(config_file,path_max,"%s",filename);
        }else{
 #ifdef WIN32
                const char *appdata=getenv("APPDATA");
                if (appdata){
-                       snprintf(_config_file,sizeof(_config_file),"%s\\%s",appdata,LINPHONE_CONFIG_DIR);
-                       CreateDirectory(_config_file,NULL);
-                       snprintf(_config_file,sizeof(_config_file),"%s\\%s",appdata,LINPHONE_CONFIG_DIR "\\" CONFIG_FILE);
+                       snprintf(config_file,path_max,"%s\\%s",appdata,LINPHONE_CONFIG_DIR);
+                       CreateDirectory(config_file,NULL);
+                       snprintf(config_file,path_max,"%s\\%s\\%s",appdata,LINPHONE_CONFIG_DIR,filename);
                }
 #else
                const char *home=getenv("HOME");
                if (home==NULL) home=".";
-               snprintf(_config_file,sizeof(_config_file),"%s/%s",home,CONFIG_FILE);
+               snprintf(config_file,path_max,"%s/%s",home,filename);
 #endif
        }
-       return _config_file;
+       return config_file;
 }
 
-
 #define FACTORY_CONFIG_FILE "linphonerc.factory"
 static char _factory_config_file[1024];
 static const char *linphone_gtk_get_factory_config_file(){
@@ -162,7 +181,7 @@ static const char *linphone_gtk_get_factory_config_file(){
                                                 "%s",FACTORY_CONFIG_FILE);
        } else {
                char *progdir;
-               
+
                if (progpath != NULL) {
                        char *basename;
                        progdir = strdup(progpath);
@@ -201,12 +220,12 @@ static const char *linphone_gtk_get_factory_config_file(){
 }
 
 static void linphone_gtk_init_liblinphone(const char *config_file,
-               const char *factory_config_file) {
+               const char *factory_config_file, const char *db_file) {
        LinphoneCoreVTable vtable={0};
+       gchar *secrets_file=linphone_gtk_get_config_file(SECRETS_FILE);
 
        vtable.call_state_changed=linphone_gtk_call_state_changed;
        vtable.registration_state_changed=linphone_gtk_registration_state_changed;
-       vtable.show=linphone_gtk_show;
        vtable.notify_presence_recv=linphone_gtk_notify_recv;
        vtable.new_subscription_request=linphone_gtk_new_unknown_subscriber;
        vtable.auth_info_requested=linphone_gtk_auth_info_requested;
@@ -215,17 +234,27 @@ static void linphone_gtk_init_liblinphone(const char *config_file,
        vtable.display_warning=linphone_gtk_display_warning;
        vtable.display_url=linphone_gtk_display_url;
        vtable.call_log_updated=linphone_gtk_call_log_updated;
-       vtable.text_received=linphone_gtk_text_received;
+       //vtable.text_received=linphone_gtk_text_received;
+       vtable.message_received=linphone_gtk_text_received;
        vtable.refer_received=linphone_gtk_refer_received;
        vtable.buddy_info_updated=linphone_gtk_buddy_info_updated;
+       vtable.call_encryption_changed=linphone_gtk_call_encryption_changed;
+       vtable.transfer_state_changed=linphone_gtk_transfer_state_changed;
 
-       linphone_core_set_user_agent("Linphone", LINPHONE_VERSION);
        the_core=linphone_core_new(&vtable,config_file,factory_config_file,NULL);
+       //lp_config_set_int(linphone_core_get_config(the_core), "sip", "store_auth_info", 0);
+       linphone_core_set_user_agent(the_core,"Linphone", LINPHONE_VERSION);
        linphone_core_set_waiting_callback(the_core,linphone_gtk_wait,NULL);
+       linphone_core_set_zrtp_secrets_file(the_core,secrets_file);
+       g_free(secrets_file);
+       linphone_core_enable_video(the_core,TRUE,TRUE);
+       if (no_video) {
+               _linphone_gtk_enable_video(FALSE);
+               linphone_gtk_set_ui_config_int("videoselfview",0);
+       }
+       if (db_file) linphone_core_set_chat_database_path(the_core,db_file);
 }
 
-
-
 LinphoneCore *linphone_gtk_get_core(void){
        return the_core;
 }
@@ -234,6 +263,11 @@ GtkWidget *linphone_gtk_get_main_window(){
        return the_ui;
 }
 
+void linphone_gtk_destroy_main_window() {
+       linphone_gtk_destroy_window(the_ui);    
+       the_ui = NULL;
+}
+
 static void linphone_gtk_configure_window(GtkWidget *w, const char *window_name){
        static const char *icon_path=NULL;
        static const char *hiddens=NULL;
@@ -252,8 +286,10 @@ static void linphone_gtk_configure_window(GtkWidget *w, const char *window_name)
                linphone_gtk_visibility_set(shown,window_name,w,TRUE);
        if (icon_path) {
                GdkPixbuf *pbuf=create_pixbuf(icon_path);
-               gtk_window_set_icon(GTK_WINDOW(w),pbuf);
-               g_object_unref(G_OBJECT(pbuf));
+               if(pbuf != NULL) {
+                       gtk_window_set_icon(GTK_WINDOW(w),pbuf);
+                       g_object_unref(G_OBJECT(pbuf));
+               }
        }
 }
 
@@ -270,6 +306,12 @@ static int get_ui_file(const char *name, char *path, int pathsize){
        return 0;
 }
 
+void linphone_gtk_destroy_window(GtkWidget *widget) {
+       GtkBuilder* builder = g_object_get_data(G_OBJECT(widget), "builder");
+       gtk_widget_destroy(widget);
+       g_object_unref (G_OBJECT (builder));
+}
+
 GtkWidget *linphone_gtk_create_window(const char *window_name){
        GError* error = NULL;
        GtkBuilder* builder = gtk_builder_new ();
@@ -277,7 +319,7 @@ GtkWidget *linphone_gtk_create_window(const char *window_name){
        GtkWidget *w;
 
        if (get_ui_file(window_name,path,sizeof(path))==-1) return NULL;
-       
+
        if (!gtk_builder_add_from_file (builder, path, &error)){
                g_error("Couldn't load builder file: %s", error->message);
                g_error_free (error);
@@ -288,7 +330,7 @@ GtkWidget *linphone_gtk_create_window(const char *window_name){
                g_error("Could not retrieve '%s' window from xml file",window_name);
                return NULL;
        }
-       g_object_set_data(G_OBJECT(w),"builder",builder);
+       g_object_set_data(G_OBJECT(w), "builder",builder);
        gtk_builder_connect_signals(builder,w);
        linphone_gtk_configure_window(w,window_name);
        return w;
@@ -302,7 +344,7 @@ GtkWidget *linphone_gtk_create_widget(const char *filename, const char *widget_n
        gchar *object_ids[2];
        object_ids[0]=g_strdup(widget_name);
        object_ids[1]=NULL;
-       
+
        if (get_ui_file(filename,path,sizeof(path))==-1) return NULL;
        if (!gtk_builder_add_objects_from_file(builder,path,object_ids,&error)){
                g_error("Couldn't load %s from builder file %s: %s", widget_name,path,error->message);
@@ -317,13 +359,21 @@ GtkWidget *linphone_gtk_create_widget(const char *filename, const char *widget_n
                return NULL;
        }
        g_object_set_data(G_OBJECT(w),"builder",builder);
+       g_signal_connect_swapped(G_OBJECT(w),"destroy",(GCallback)g_object_unref,builder);
        gtk_builder_connect_signals(builder,w);
        return w;
 }
 
+static void entry_unmapped(GtkWidget *entry){
+       g_message("Entry is unmapped, calling unrealize to workaround chinese bug.");
+       gtk_widget_unrealize(entry);
+}
+
 GtkWidget *linphone_gtk_get_widget(GtkWidget *window, const char *name){
-       GtkBuilder *builder=(GtkBuilder*)g_object_get_data(G_OBJECT(window),"builder");
+       GtkBuilder *builder;
        GObject *w;
+       if (window==NULL) return NULL;
+       builder=(GtkBuilder*)g_object_get_data(G_OBJECT(window),"builder");
        if (builder==NULL){
                g_error("Fail to retrieve builder from window !");
                return NULL;
@@ -332,6 +382,15 @@ GtkWidget *linphone_gtk_get_widget(GtkWidget *window, const char *name){
        if (w==NULL){
                g_error("No widget named %s found in xml interface.",name);
        }
+       if (workaround_gtk_entry_chinese_bug){
+               if (strcmp(G_OBJECT_TYPE_NAME(w),"GtkEntry")==0){
+                       if (g_object_get_data(G_OBJECT(w),"entry_bug_workaround")==NULL){
+                               g_object_set_data(G_OBJECT(w),"entry_bug_workaround",GINT_TO_POINTER(1));
+                               g_message("%s is a GtkEntry",name);
+                               g_signal_connect(G_OBJECT(w),"unmap",(GCallback)entry_unmapped,NULL);
+                       }
+               }
+       }
        return GTK_WIDGET(w);
 }
 
@@ -339,7 +398,7 @@ GtkWidget *linphone_gtk_get_widget(GtkWidget *window, const char *name){
 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)
        {
@@ -395,7 +454,7 @@ void linphone_gtk_show_about(){
        GdkPixbuf *logo=create_pixbuf(
            linphone_gtk_get_ui_config("logo","linphone-banner.png"));
        static const char *defcfg="defcfg";
-       
+
        about=linphone_gtk_create_window("about");
        gtk_about_dialog_set_url_hook(about_url_clicked,NULL,NULL);
        memset(&filestat,0,sizeof(filestat));
@@ -437,6 +496,7 @@ static void set_video_window_decorations(GdkWindow *w){
        const char *icon_path=linphone_gtk_get_ui_config("icon",LINPHONE_ICON);
        char video_title[256];
        GdkPixbuf *pbuf=create_pixbuf(icon_path);
+
        if (!linphone_core_in_call(linphone_gtk_get_core())){
                snprintf(video_title,sizeof(video_title),"%s video",title);
                /* When not in call, treat the video as a normal window */
@@ -490,7 +550,7 @@ static gboolean linphone_gtk_iterate(LinphoneCore *lc){
        static unsigned long previd=0;
        static unsigned long preview_previd=0;
        static gboolean in_iterate=FALSE;
-       
+
        /*avoid reentrancy*/
        if (in_iterate) return TRUE;
        in_iterate=TRUE;
@@ -508,7 +568,7 @@ static gboolean linphone_gtk_iterate(LinphoneCore *lc){
                if (id!=0){
                        ms_message("Updating window decorations");
 #ifndef WIN32
-                       w=gdk_window_foreign_new(id);
+                       w=gdk_window_foreign_new((GdkNativeWindow)id);
 #else
                        w=gdk_window_foreign_new((HANDLE)id);
 #endif
@@ -527,7 +587,7 @@ static gboolean linphone_gtk_iterate(LinphoneCore *lc){
                if (id!=0){
                        ms_message("Updating window decorations for preview");
 #ifndef WIN32
-                       w=gdk_window_foreign_new(id);
+                       w=gdk_window_foreign_new((GdkNativeWindow)id);
 #else
                        w=gdk_window_foreign_new((HANDLE)id);
 #endif
@@ -604,8 +664,8 @@ static void save_uri_history(){
 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)){ 
+
+       if (gtk_tree_model_get_iter_first(model,&iter)){
                do {
                        gchar *uri=NULL;
                        gtk_tree_model_get(model,&iter,0,&uri,-1);
@@ -626,28 +686,23 @@ static void completion_add_text(GtkEntry *entry, const char *text){
        save_uri_history();
 }
 
+bool_t linphone_gtk_video_enabled(void){
+       const LinphoneVideoPolicy *vpol=linphone_core_get_video_policy(linphone_gtk_get_core());
+       return vpol->automatically_accept && vpol->automatically_initiate;
+}
 
 void linphone_gtk_show_main_window(){
        GtkWidget *w=linphone_gtk_get_main_window();
        LinphoneCore *lc=linphone_gtk_get_core();
-       if (linphone_core_video_enabled(lc)){
-               linphone_core_enable_video_preview(lc,linphone_gtk_get_ui_config_int("videoselfview",
+       linphone_core_enable_video_preview(lc,linphone_gtk_get_ui_config_int("videoselfview",
                VIDEOSELFVIEW_DEFAULT));
-       }
        gtk_widget_show(w);
        gtk_window_present(GTK_WINDOW(w));
 }
 
-static void linphone_gtk_show(LinphoneCore *lc){
-#ifndef HAVE_NOTIFY
-       linphone_gtk_show_main_window();
-#endif
-}
-
 void linphone_gtk_call_terminated(LinphoneCall *call, const char *error){
        GtkWidget *mw=linphone_gtk_get_main_window();
        if (linphone_core_get_calls(linphone_gtk_get_core())==NULL){
-           gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"terminate_call"),FALSE);
            gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"start_call"),TRUE);
        }
        if (linphone_gtk_use_in_call_view() && call)
@@ -661,102 +716,167 @@ static void linphone_gtk_update_call_buttons(LinphoneCall *call){
        const MSList *calls=linphone_core_get_calls(lc);
        GtkWidget *button;
        bool_t start_active=TRUE;
-       bool_t stop_active=FALSE;
+       //bool_t stop_active=FALSE;
        bool_t add_call=FALSE;
        int call_list_size=ms_list_size(calls);
-       
+
        if (calls==NULL){
                start_active=TRUE;
-               stop_active=FALSE;
+               //stop_active=FALSE;
        }else{
-               stop_active=TRUE;       
+               //stop_active=TRUE;
                start_active=TRUE;
                add_call=TRUE;
        }
        button=linphone_gtk_get_widget(mw,"start_call");
        gtk_widget_set_sensitive(button,start_active);
        gtk_widget_set_visible(button,!add_call);
-       
+
        button=linphone_gtk_get_widget(mw,"add_call");
-       gtk_widget_set_sensitive(button,start_active);
+       if (linphone_core_sound_resources_locked(lc) || (call && linphone_call_get_state(call)==LinphoneCallIncomingReceived)) {
+               gtk_widget_set_sensitive(button,FALSE);
+       } else {
+               gtk_widget_set_sensitive(button,start_active);
+       }
        gtk_widget_set_visible(button,add_call);
-       
-       gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"terminate_call"),stop_active);
 
-       linphone_gtk_enable_transfer_button(lc,call_list_size>1);
-       linphone_gtk_enable_conference_button(lc,call_list_size>1);
+       //gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"terminate_call"),stop_active);
+       GtkWidget *conf_frame=(GtkWidget *)g_object_get_data(G_OBJECT(mw),"conf_frame");
+       if(conf_frame==NULL){
+               linphone_gtk_enable_transfer_button(lc,call_list_size>1);
+               linphone_gtk_enable_conference_button(lc,call_list_size>1);
+       } else {
+               linphone_gtk_enable_transfer_button(lc,FALSE);
+               linphone_gtk_enable_conference_button(lc,FALSE);
+       }
        update_video_title();
+       if (call) {
+               linphone_gtk_update_video_button(call);
+       }
+}
+
+gchar *linphone_gtk_get_record_path(const LinphoneAddress *address, gboolean is_conference){
+       const char *dir=g_get_user_special_dir(G_USER_DIRECTORY_MUSIC);
+       const char *id="unknown";
+       char filename[256]={0};
+       char date[64]={0};
+       time_t curtime=time(NULL);
+       struct tm loctime;
+       
+#ifdef WIN32
+       loctime=*localtime(&curtime);
+#else
+       localtime_r(&curtime,&loctime);
+#endif
+       snprintf(date,sizeof(date)-1,"%i%02i%02i-%02i%02i",loctime.tm_year+1900,loctime.tm_mon+1,loctime.tm_mday, loctime.tm_hour, loctime.tm_min);
+       
+       if (address){
+               id=linphone_address_get_username(address);
+               if (id==NULL) id=linphone_address_get_domain(address);
+       }
+       if (is_conference){
+               snprintf(filename,sizeof(filename)-1,"%s-conference-%s.wav",
+                       linphone_gtk_get_ui_config("title","Linphone"),
+                       date);
+       }else{
+               snprintf(filename,sizeof(filename)-1,"%s-call-%s-%s.wav",
+                       linphone_gtk_get_ui_config("title","Linphone"),
+                       date,
+                       id);
+       }
+       return g_build_filename(dir,filename,NULL);
 }
 
 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)!=NULL) {
+       LinphoneCore *lc=linphone_gtk_get_core();
+       LinphoneAddress *addr=linphone_core_interpret_url(lc,entered);
+       
+       if (addr!=NULL){
+               LinphoneCallParams *params=linphone_core_create_default_call_parameters(lc);
+               gchar *record_file=linphone_gtk_get_record_path(addr,FALSE);
+               linphone_call_params_set_record_file(params,record_file);
+               linphone_core_invite_address_with_params(lc,addr,params);
                completion_add_text(GTK_ENTRY(uri_bar),entered);
+               linphone_address_destroy(addr);
+               linphone_call_params_destroy(params);
+               g_free(record_file);
        }else{
                linphone_gtk_call_terminated(NULL,NULL);
        }
        return FALSE;
 }
 
+
+static void accept_incoming_call(LinphoneCall *call){
+       LinphoneCore *lc=linphone_gtk_get_core();
+       LinphoneCallParams *params=linphone_core_create_default_call_parameters(lc);
+       gchar *record_file=linphone_gtk_get_record_path(linphone_call_get_remote_address(call),FALSE);
+       linphone_call_params_set_record_file(params,record_file);
+       linphone_core_accept_call_with_params(lc,call,params);
+       linphone_call_params_destroy(params);
+}
+
 static gboolean linphone_gtk_auto_answer(LinphoneCall *call){
-       if (linphone_call_get_state(call)==LinphoneCallIncomingReceived){
-               linphone_core_accept_call (linphone_gtk_get_core(),call);
-               linphone_call_unref(call);
+       LinphoneCallState state=linphone_call_get_state(call);
+       if (state==LinphoneCallIncomingReceived || state==LinphoneCallIncomingEarlyMedia){
+               accept_incoming_call(call);
        }
        return FALSE;
 }
 
-
 void linphone_gtk_start_call(GtkWidget *w){
-       LinphoneCore *lc=linphone_gtk_get_core();
-       LinphoneCall *call;
+       LinphoneCall *call=linphone_gtk_get_currently_displayed_call(NULL);
        /*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");
+       LinphoneCallState state= call ? linphone_call_get_state(call) : LinphoneCallIdle;
 
-       call=linphone_gtk_get_currently_displayed_call();
-       if (call!=NULL && linphone_call_get_state(call)==LinphoneCallIncomingReceived){
-               linphone_core_accept_call(lc,call);
+       if (state == LinphoneCallIncomingReceived || state == LinphoneCallIncomingEarlyMedia){
+               accept_incoming_call(call);
        }else{
                /*immediately disable the button and delay a bit the execution the linphone_core_invite()
                so that we don't freeze the button. linphone_core_invite() might block for some hundreds of milliseconds*/
                gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"start_call"),FALSE);
                g_timeout_add(100,(GSourceFunc)linphone_gtk_start_call_do,uri_bar);
        }
-       
+
 }
 
 void linphone_gtk_uri_bar_activate(GtkWidget *w){
        linphone_gtk_start_call(w);
 }
 
-
 void linphone_gtk_terminate_call(GtkWidget *button){
-       LinphoneCall *call=linphone_gtk_get_currently_displayed_call ();
-       if (call)
+       gboolean is_conf;
+       LinphoneCall *call=linphone_gtk_get_currently_displayed_call(&is_conf);
+       if (call){
                linphone_core_terminate_call(linphone_gtk_get_core(),call);
+       }else if (is_conf){
+               linphone_core_terminate_conference(linphone_gtk_get_core());
+       }
 }
 
 void linphone_gtk_decline_clicked(GtkWidget *button){
-       LinphoneCall *call=linphone_gtk_get_currently_displayed_call ();
+       LinphoneCall *call=linphone_gtk_get_currently_displayed_call(NULL);
        if (call)
                linphone_core_terminate_call(linphone_gtk_get_core(),call);
 }
 
 void linphone_gtk_answer_clicked(GtkWidget *button){
-       LinphoneCall *call=linphone_gtk_get_currently_displayed_call ();
+       LinphoneCall *call=linphone_gtk_get_currently_displayed_call(NULL);
        if (call){
-               linphone_core_pause_all_calls(linphone_gtk_get_core());
-               linphone_core_accept_call(linphone_gtk_get_core(),call);
+               accept_incoming_call(call);
                linphone_gtk_show_main_window(); /* useful when the button is clicked on a notification */
        }
 }
 
-void linphone_gtk_enable_video(GtkWidget *w){
-       gboolean val=gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
-       GtkWidget *selfview_item=linphone_gtk_get_widget(linphone_gtk_get_main_window(),"selfview_item");
-       linphone_core_enable_video(linphone_gtk_get_core(),val,val);
-       gtk_widget_set_sensitive(selfview_item,val);
+void _linphone_gtk_enable_video(gboolean val){
+       LinphoneVideoPolicy policy={0};
+       policy.automatically_initiate=policy.automatically_accept=val;
+       linphone_core_enable_video(linphone_gtk_get_core(),TRUE,TRUE);
+       linphone_core_set_video_policy(linphone_gtk_get_core(),&policy);
+
        if (val){
                linphone_core_enable_video_preview(linphone_gtk_get_core(),
                linphone_gtk_get_ui_config_int("videoselfview",VIDEOSELFVIEW_DEFAULT));
@@ -765,6 +885,12 @@ void linphone_gtk_enable_video(GtkWidget *w){
        }
 }
 
+void linphone_gtk_enable_video(GtkWidget *w){
+       gboolean val=gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
+       //GtkWidget *selfview_item=linphone_gtk_get_widget(linphone_gtk_get_main_window(),"selfview_item");
+       _linphone_gtk_enable_video(val);
+}
+
 void linphone_gtk_enable_self_view(GtkWidget *w){
        gboolean val=gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
        LinphoneCore *lc=linphone_gtk_get_core();
@@ -783,6 +909,17 @@ void linphone_gtk_used_identity_changed(GtkWidget *w){
        if (sel) g_free(sel);
 }
 
+void on_proxy_refresh_button_clicked(GtkWidget *w){
+       LinphoneCore *lc=linphone_gtk_get_core();
+       MSList const *item=linphone_core_get_proxy_config_list(lc);
+       while (item != NULL) {
+               LinphoneProxyConfig *lpc=(LinphoneProxyConfig*)item->data;
+               linphone_proxy_config_edit(lpc);
+               linphone_proxy_config_done(lpc);
+               item = item->next;
+       }
+}
+
 static void linphone_gtk_notify_recv(LinphoneCore *lc, LinphoneFriend * fid){
        linphone_gtk_show_friends();
 }
@@ -825,7 +962,6 @@ typedef struct _AuthTimeout{
        GtkWidget *w;
 } AuthTimeout;
 
-
 static void auth_timeout_clean(AuthTimeout *tout){
        tout->w=NULL;
 }
@@ -877,7 +1013,7 @@ static void linphone_gtk_auth_info_requested(LinphoneCore *lc, const char *realm
        LinphoneAuthInfo *info;
        gchar *msg;
        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);
@@ -899,6 +1035,7 @@ static void linphone_gtk_auth_info_requested(LinphoneCore *lc, const char *realm
 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);
@@ -925,23 +1062,56 @@ static void linphone_gtk_call_log_updated(LinphoneCore *lc, LinphoneCallLog *cl)
 }
 
 #ifdef HAVE_NOTIFY
-static void make_notification(const char *title, const char *body){
-       NotifyNotification *n;
-       n = notify_notification_new(title,body,linphone_gtk_get_ui_config("icon",LINPHONE_ICON));
+static bool_t notify_actions_supported() {
+       bool_t accepts_actions = FALSE;
+       GList *capabilities = notify_get_server_caps();
+       GList *c;
+       if(capabilities != NULL) {
+               for(c = capabilities; c != NULL; c = c->next) {
+                       if(strcmp((char*)c->data, "actions") == 0 ) {
+                               accepts_actions = TRUE;
+                               break;
+                       }
+               }
+               g_list_foreach(capabilities, (GFunc)g_free, NULL);
+               g_list_free(capabilities);
+       }
+       return accepts_actions;
+}
+
+static NotifyNotification* build_notification(const char *title, const char *body){
+        return notify_notification_new(title,body,linphone_gtk_get_ui_config("icon",LINPHONE_ICON)
+#ifdef HAVE_NOTIFY1
+        ,NULL
+#endif
+       );
+}
+
+static void show_notification(NotifyNotification* n){
        if (n && !notify_notification_show(n,NULL))
-                       ms_error("Failed to send notification.");
+               ms_error("Failed to send notification.");
+}
+
+static void make_notification(const char *title, const char *body){
+       show_notification(build_notification(title,body));
 }
 
 #endif
 
-static void linphone_gtk_notify(LinphoneCall *call, const char *msg){
+void linphone_gtk_notify(LinphoneCall *call, const char *msg){
 #ifdef HAVE_NOTIFY
        if (!notify_is_initted())
                if (!notify_init ("Linphone")) ms_error("Libnotify failed to init.");
 #endif
        if (!call) {
+
 #ifdef HAVE_NOTIFY
-               if (!notify_notification_show(notify_notification_new("Linphone",msg,NULL),NULL))
+               if (!notify_notification_show(notify_notification_new("Linphone",msg,NULL
+#ifdef HAVE_NOTIFY1
+       ,NULL
+#endif
+),NULL))
+
                                ms_error("Failed to send notification.");
 #else
                linphone_gtk_show_main_window();
@@ -950,18 +1120,26 @@ static void linphone_gtk_notify(LinphoneCall *call, const char *msg){
 #ifdef HAVE_NOTIFY
                char *body=NULL;
                char *remote=call!=NULL ? linphone_call_get_remote_address_as_string(call) : NULL;
+               NotifyNotification *n;
                switch(linphone_call_get_state(call)){
                        case LinphoneCallError:
-                               make_notification(_("Call error"),body=g_markup_printf_escaped("<span size=\"large\">%s</span>\n%s",msg,remote));
+                               make_notification(_("Call error"),body=g_markup_printf_escaped("<b>%s</b>\n%s",msg,remote));
                        break;
                        case LinphoneCallEnd:
-                               make_notification(_("Call ended"),body=g_markup_printf_escaped("<span size=\"large\">%s</span>",remote));
+                               make_notification(_("Call ended"),body=g_markup_printf_escaped("<b>%s</b>",remote));
                        break;
                        case LinphoneCallIncomingReceived:
-                               make_notification(_("Incoming call"),body=g_markup_printf_escaped("<span size=\"large\">%s</span>",remote));
+                               n=build_notification(_("Incoming call"),body=g_markup_printf_escaped("<b>%s</b>",remote));
+                               if (notify_actions_supported()) {
+                                       notify_notification_add_action (n,"answer", _("Answer"),
+                                               NOTIFY_ACTION_CALLBACK(linphone_gtk_answer_clicked),NULL,NULL);
+                                       notify_notification_add_action (n,"decline",_("Decline"),
+                                               NOTIFY_ACTION_CALLBACK(linphone_gtk_decline_clicked),NULL,NULL);
+                               }
+                               show_notification(n);
                        break;
                        case LinphoneCallPausedByRemote:
-                               make_notification(_("Call paused"),body=g_markup_printf_escaped("<span size=\"large\">by %s</span>",remote));
+                               make_notification(_("Call paused"),body=g_markup_printf_escaped(_("<b>by %s</b>"),remote));
                        break;
                        default:
                        break;
@@ -972,6 +1150,52 @@ static void linphone_gtk_notify(LinphoneCall *call, const char *msg){
        }
 }
 
+static void on_call_updated_response(GtkWidget *dialog, gint responseid, LinphoneCall *call){
+       if (linphone_call_get_state(call)==LinphoneCallUpdatedByRemote){
+               LinphoneCore *lc=linphone_call_get_core(call);
+               LinphoneCallParams *params=linphone_call_params_copy(linphone_call_get_current_params(call));
+               linphone_call_params_enable_video(params,responseid==GTK_RESPONSE_YES);
+               linphone_core_accept_call_update(lc,call,params);
+               linphone_call_params_destroy(params);
+       }
+       linphone_call_unref(call);
+       g_source_remove_by_user_data(dialog);
+       gtk_widget_destroy(dialog);
+}
+
+static void on_call_updated_timeout(GtkWidget *dialog){
+       gtk_widget_destroy(dialog);
+}
+
+static void linphone_gtk_call_updated_by_remote(LinphoneCall *call){
+       LinphoneCore *lc=linphone_call_get_core(call);
+       const LinphoneVideoPolicy *pol=linphone_core_get_video_policy(lc);
+       const LinphoneCallParams *rparams=linphone_call_get_remote_params(call);
+       const LinphoneCallParams *current_params=linphone_call_get_current_params(call);
+       gboolean video_requested=linphone_call_params_video_enabled(rparams);
+       gboolean video_used=linphone_call_params_video_enabled(current_params);
+       g_message("Video used=%i, video requested=%i, automatically_accept=%i",
+                 video_used,video_requested,pol->automatically_accept);
+       if (video_used==FALSE && video_requested && !pol->automatically_accept){
+               linphone_core_defer_call_update(lc,call);
+               {
+                       const LinphoneAddress *addr=linphone_call_get_remote_address(call);
+                       GtkWidget *dialog;
+                       const char *dname=linphone_address_get_display_name(addr);
+                       if (dname==NULL) dname=linphone_address_get_username(addr);
+                       if (dname==NULL) dname=linphone_address_get_domain(addr);
+                       dialog=gtk_message_dialog_new(GTK_WINDOW(linphone_gtk_get_main_window()),
+                                                                GTK_DIALOG_DESTROY_WITH_PARENT,
+                                                                GTK_MESSAGE_WARNING,
+                                                                GTK_BUTTONS_YES_NO,
+                                                                _("%s proposed to start video. Do you accept ?"),dname);
+                       g_signal_connect(G_OBJECT(dialog),"response",(GCallback)on_call_updated_response,linphone_call_ref(call));
+                       g_timeout_add(20000,(GSourceFunc)on_call_updated_timeout,dialog);
+                       gtk_widget_show(dialog);
+               }
+       }
+}
+
 static void linphone_gtk_call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cs, const char *msg){
        switch(cs){
                case LinphoneCallOutgoingInit:
@@ -983,6 +1207,9 @@ static void linphone_gtk_call_state_changed(LinphoneCore *lc, LinphoneCall *call
                case LinphoneCallStreamsRunning:
                        linphone_gtk_in_call_view_set_in_call(call);
                break;
+               case LinphoneCallUpdatedByRemote:
+                       linphone_gtk_call_updated_by_remote(call);
+               break;
                case LinphoneCallError:
                        linphone_gtk_in_call_view_terminate (call,msg);
                break;
@@ -991,13 +1218,13 @@ static void linphone_gtk_call_state_changed(LinphoneCore *lc, LinphoneCall *call
                        linphone_gtk_status_icon_set_blinking(FALSE);
                break;
                case LinphoneCallIncomingReceived:
-                       linphone_gtk_create_in_call_view (call);
+                       linphone_gtk_create_in_call_view(call);
                        linphone_gtk_in_call_view_set_incoming(call);
                        linphone_gtk_status_icon_set_blinking(TRUE);
                        if (auto_answer)  {
                                linphone_call_ref(call);
                                g_timeout_add(2000,(GSourceFunc)linphone_gtk_auto_answer ,call);
-                       }               
+                       }
                break;
                case LinphoneCallResuming:
                        linphone_gtk_enable_hold_button(call,TRUE,TRUE);
@@ -1005,8 +1232,10 @@ static void linphone_gtk_call_state_changed(LinphoneCore *lc, LinphoneCall *call
                break;
                case LinphoneCallPausing:
                        linphone_gtk_enable_hold_button(call,TRUE,FALSE);
+                       linphone_gtk_call_update_tab_header(call,FALSE);
                case LinphoneCallPausedByRemote:
                        linphone_gtk_in_call_view_set_paused(call);
+                       linphone_gtk_call_update_tab_header(call,TRUE);
                break;
                case LinphoneCallConnected:
                        linphone_gtk_enable_hold_button (call,TRUE,TRUE);
@@ -1019,13 +1248,21 @@ static void linphone_gtk_call_state_changed(LinphoneCore *lc, LinphoneCall *call
        linphone_gtk_update_call_buttons (call);
 }
 
+static void linphone_gtk_call_encryption_changed(LinphoneCore *lc, LinphoneCall *call, bool_t enabled, const char *token){
+       linphone_gtk_in_call_view_show_encryption(call);
+}
+
+static void linphone_gtk_transfer_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate){
+       linphone_gtk_in_call_view_set_transfer_status(call,cstate);
+}
+
 static void update_registration_status(LinphoneProxyConfig *cfg, LinphoneRegistrationState rs){
        GtkComboBox *box=GTK_COMBO_BOX(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"identities"));
        GtkTreeModel *model=gtk_combo_box_get_model(box);
        GtkTreeIter iter;
        gboolean found=FALSE;
        const char *stock_id=NULL;
-       
+
        if (gtk_tree_model_get_iter_first(model,&iter)){
                gpointer p;
                do{
@@ -1059,7 +1296,7 @@ static void update_registration_status(LinphoneProxyConfig *cfg, LinphoneRegistr
        gtk_list_store_set(GTK_LIST_STORE(model),&iter,1,stock_id,-1);
 }
 
-static void linphone_gtk_registration_state_changed(LinphoneCore *lc, LinphoneProxyConfig *cfg, 
+static void linphone_gtk_registration_state_changed(LinphoneCore *lc, LinphoneProxyConfig *cfg,
                                                     LinphoneRegistrationState rs, const char *msg){
        switch (rs){
                case LinphoneRegistrationOk:
@@ -1076,12 +1313,6 @@ static void linphone_gtk_registration_state_changed(LinphoneCore *lc, LinphonePr
        update_registration_status(cfg,rs);
 }
 
-
-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);
-}
-
 void linphone_gtk_open_browser(const char *url){
        /*in gtk 2.16, gtk_show_uri does not work...*/
 #ifndef WIN32
@@ -1102,19 +1333,28 @@ void linphone_gtk_link_to_website(GtkWidget *item){
        linphone_gtk_open_browser(home);
 }
 
+#ifndef HAVE_GTK_OSX
+
+static GtkStatusIcon *icon=NULL;
+
+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);
+}
+
 static GtkWidget *create_icon_menu(){
        GtkWidget *menu=gtk_menu_new();
        GtkWidget *menu_item;
        GtkWidget *image;
        gchar *tmp;
        const gchar *homesite;
-       
+
        homesite=linphone_gtk_get_ui_config("home","http://www.linphone.org");
        menu_item=gtk_image_menu_item_new_with_label(_("Website link"));
        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);
-       
+
        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);
@@ -1122,7 +1362,7 @@ static GtkWidget *create_icon_menu(){
        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);
-       
+
        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);
@@ -1135,7 +1375,23 @@ static GtkWidget *create_icon_menu(){
        return menu;
 }
 
-static GtkStatusIcon *icon=NULL;
+void linphone_gtk_save_main_window_position(GtkWindow* mw, GdkEvent *event, gpointer data){
+       gtk_window_get_position(GTK_WINDOW(mw), &main_window_x, &main_window_y); 
+}
+
+static void handle_icon_click() {
+       GtkWidget *mw=linphone_gtk_get_main_window();
+       if (!gtk_window_is_active((GtkWindow*)mw)) {
+               if(!gtk_widget_is_drawable(mw)){ 
+                       //we only move if window was hidden. If it was simply behind the window stack, ie, drawable, we keep it as it was
+                       gtk_window_move (GTK_WINDOW(mw), main_window_x, main_window_y);
+               }
+               linphone_gtk_show_main_window();
+       } else {
+               linphone_gtk_save_main_window_position((GtkWindow*)mw, NULL, NULL);
+               gtk_widget_hide(mw);
+       }
+}
 
 static void linphone_gtk_init_status_icon(){
        const char *icon_path=linphone_gtk_get_ui_config("icon",LINPHONE_ICON);
@@ -1145,8 +1401,10 @@ static void linphone_gtk_init_status_icon(){
        const char *title;
        title=linphone_gtk_get_ui_config("title",_("Linphone - a video internet phone"));
        icon=gtk_status_icon_new_from_pixbuf(pbuf);
+#if GTK_CHECK_VERSION(2,20,0)
        gtk_status_icon_set_name(icon,title);
-       g_signal_connect_swapped(G_OBJECT(icon),"activate",(GCallback)linphone_gtk_show_main_window,linphone_gtk_get_main_window());
+#endif
+       g_signal_connect_swapped(G_OBJECT(icon),"activate",(GCallback)handle_icon_click,NULL);
        g_signal_connect(G_OBJECT(icon),"popup-menu",(GCallback)icon_popup_menu,NULL);
        gtk_status_icon_set_tooltip(icon,title);
        gtk_status_icon_set_visible(icon,TRUE);
@@ -1170,18 +1428,37 @@ static gboolean do_icon_blink(GtkStatusIcon *gi){
        return TRUE;
 }
 
-static void linphone_gtk_status_icon_set_blinking(gboolean val){
-       guint tout;
-       tout=(unsigned)GPOINTER_TO_INT(g_object_get_data(G_OBJECT(icon),"timeout"));
-       if (val && tout==0){
-               tout=g_timeout_add(500,(GSourceFunc)do_icon_blink,icon);
-               g_object_set_data(G_OBJECT(icon),"timeout",GINT_TO_POINTER(tout));
-       }else if (!val && tout!=0){
-               GdkPixbuf *normal_icon=g_object_get_data(G_OBJECT(icon),"icon");
-               g_source_remove(tout);
-               g_object_set_data(G_OBJECT(icon),"timeout",NULL);
-               gtk_status_icon_set_from_pixbuf(icon,normal_icon);
+#endif
+
+void linphone_gtk_status_icon_set_blinking(gboolean val){
+#ifdef HAVE_GTK_OSX
+       static gint attention_id;
+       GtkosxApplication *theMacApp=gtkosx_application_get();
+       if (val)
+               attention_id=gtkosx_application_attention_request(theMacApp,CRITICAL_REQUEST);
+       else gtkosx_application_cancel_attention_request(theMacApp,attention_id);
+#else
+       if (icon!=NULL){
+               guint tout;
+               tout=(unsigned)GPOINTER_TO_INT(g_object_get_data(G_OBJECT(icon),"timeout"));
+               if (val && tout==0){
+                       tout=g_timeout_add(500,(GSourceFunc)do_icon_blink,icon);
+                       g_object_set_data(G_OBJECT(icon),"timeout",GINT_TO_POINTER(tout));
+               }else if (!val && tout!=0){
+                       GdkPixbuf *normal_icon=g_object_get_data(G_OBJECT(icon),"icon");
+                       g_source_remove(tout);
+                       g_object_set_data(G_OBJECT(icon),"timeout",NULL);
+                       gtk_status_icon_set_from_pixbuf(icon,normal_icon);
+               }
        }
+#endif
+}
+
+void linphone_gtk_options_activate(GtkWidget *item){
+#ifndef HAVE_GTK_OSX
+       gtk_widget_set_visible(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"quit_item"),
+               TRUE);
+#endif
 }
 
 static void init_identity_combo(GtkComboBox *box){
@@ -1234,8 +1511,8 @@ void linphone_gtk_load_identities(void){
 }
 
 static void linphone_gtk_dtmf_pressed(GtkButton *button){
-       const char *label=gtk_button_get_label(button);
-       GtkWidget *uri_bar=linphone_gtk_get_widget(gtk_widget_get_toplevel(GTK_WIDGET(button)),"uribar");
+       const char *label=(char *)g_object_get_data(G_OBJECT(button),"label");
+       GtkWidget *uri_bar=linphone_gtk_get_widget(linphone_gtk_get_main_window(),"uribar");
        int pos=-1;
        gtk_editable_insert_text(GTK_EDITABLE(uri_bar),label,1,&pos);
        linphone_core_play_dtmf (linphone_gtk_get_core(),label[0],-1);
@@ -1248,8 +1525,9 @@ static void linphone_gtk_dtmf_released(GtkButton *button){
        linphone_core_stop_dtmf (linphone_gtk_get_core());
 }
 
-static void linphone_gtk_connect_digits(void){
-       GtkContainer *cont=GTK_CONTAINER(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"dtmf_table"));
+
+static void linphone_gtk_connect_digits(GtkWidget *w){
+       GtkContainer *cont=GTK_CONTAINER(linphone_gtk_get_widget(w,"dtmf_table"));
        GList *children=gtk_container_get_children(cont);
        GList *elem;
        for(elem=children;elem!=NULL;elem=elem->next){
@@ -1260,14 +1538,13 @@ static void linphone_gtk_connect_digits(void){
 }
 
 static void linphone_gtk_check_menu_items(void){
-       bool_t video_enabled=linphone_core_video_enabled(linphone_gtk_get_core());
+       bool_t video_enabled=linphone_gtk_video_enabled();
        bool_t selfview=linphone_gtk_get_ui_config_int("videoselfview",VIDEOSELFVIEW_DEFAULT);
        GtkWidget *selfview_item=linphone_gtk_get_widget(
                                        linphone_gtk_get_main_window(),"selfview_item");
        gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(linphone_gtk_get_widget(
                                        linphone_gtk_get_main_window(),"enable_video_item")), video_enabled);
        gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(selfview_item),selfview);
-       gtk_widget_set_sensitive(selfview_item,video_enabled);
 }
 
 static gboolean linphone_gtk_can_manage_accounts(){
@@ -1288,18 +1565,17 @@ static void linphone_gtk_configure_main_window(){
        static const char *home;
        static const char *start_call_icon;
        static const char *add_call_icon;
-       static const char *stop_call_icon;
        static const char *search_icon;
        static gboolean update_check_menu;
        static gboolean buttons_have_borders;
        static gboolean show_abcd;
        GtkWidget *w=linphone_gtk_get_main_window();
+
        if (!config_loaded){
                title=linphone_gtk_get_ui_config("title","Linphone");
                home=linphone_gtk_get_ui_config("home","http://www.linphone.org");
                start_call_icon=linphone_gtk_get_ui_config("start_call_icon","startcall-green.png");
                add_call_icon=linphone_gtk_get_ui_config("add_call_icon","addcall-green.png");
-               stop_call_icon=linphone_gtk_get_ui_config("stop_call_icon","stopcall-red.png");
                search_icon=linphone_gtk_get_ui_config("directory_search_icon",NULL);
                update_check_menu=linphone_gtk_get_ui_config_int("update_check_menu",0);
                buttons_have_borders=linphone_gtk_get_ui_config_int("buttons_border",1);
@@ -1322,16 +1598,12 @@ static void linphone_gtk_configure_main_window(){
                if (!buttons_have_borders)
                        gtk_button_set_relief(GTK_BUTTON(linphone_gtk_get_widget(w,"add_call")),GTK_RELIEF_NONE);
        }
-       if (stop_call_icon){
-               gtk_button_set_image(GTK_BUTTON(linphone_gtk_get_widget(w,"terminate_call")),
-                                   create_pixmap (stop_call_icon));
-               if (!buttons_have_borders)
-                       gtk_button_set_relief(GTK_BUTTON(linphone_gtk_get_widget(w,"terminate_call")),GTK_RELIEF_NONE);
-       }
        if (search_icon){
                GdkPixbuf *pbuf=create_pixbuf(search_icon);
-               gtk_image_set_from_pixbuf(GTK_IMAGE(linphone_gtk_get_widget(w,"directory_search_button_icon")),pbuf);
-               g_object_unref(G_OBJECT(pbuf));
+               if(pbuf != NULL) {
+                       gtk_image_set_from_pixbuf(GTK_IMAGE(linphone_gtk_get_widget(w,"directory_search_button_icon")),pbuf);
+                       g_object_unref(G_OBJECT(pbuf));
+               }
        }
        if (home){
                gchar *tmp;
@@ -1349,24 +1621,19 @@ static void linphone_gtk_configure_main_window(){
                */
        }
        {
-               GdkPixbuf *pbuf=create_pixbuf("dialer-orange.png");
+               GdkPixbuf *pbuf=create_pixbuf("dialer.png");
                if (pbuf) {
-                       gtk_image_set_from_pixbuf(GTK_IMAGE(linphone_gtk_get_widget(w,"keypad_tab_icon")),pbuf);
-                       g_object_unref(G_OBJECT(pbuf));
+                       GtkButton *button=GTK_BUTTON(linphone_gtk_get_widget(w,"keypad"));
+                       gtk_button_set_image(button,gtk_image_new_from_pixbuf (pbuf));
                }
        }
-       if (linphone_gtk_can_manage_accounts())
+       if (linphone_gtk_can_manage_accounts()) {
                gtk_widget_show(linphone_gtk_get_widget(w,"assistant_item"));
+       }
        if (update_check_menu){
                gtk_widget_show(linphone_gtk_get_widget(w,"versioncheck_item"));
        }
-       if (!show_abcd){
-               gtk_widget_hide(linphone_gtk_get_widget(w,"dtmf_A"));
-               gtk_widget_hide(linphone_gtk_get_widget(w,"dtmf_B"));
-               gtk_widget_hide(linphone_gtk_get_widget(w,"dtmf_C"));
-               gtk_widget_hide(linphone_gtk_get_widget(w,"dtmf_D"));
-               gtk_table_resize(GTK_TABLE(linphone_gtk_get_widget(w,"dtmf_table")),4,3);
-       }
+       g_object_set_data(G_OBJECT(w),"show_abcd",GINT_TO_POINTER(show_abcd));
 }
 
 void linphone_gtk_manage_login(void){
@@ -1381,7 +1648,6 @@ void linphone_gtk_manage_login(void){
        }
 }
 
-
 gboolean linphone_gtk_close(GtkWidget *mw){
        /*shutdown calls if any*/
        LinphoneCore *lc=linphone_gtk_get_core();
@@ -1399,48 +1665,90 @@ gboolean linphone_gtk_close(GtkWidget *mw){
 
 #ifdef HAVE_GTK_OSX
 static gboolean on_window_state_event(GtkWidget *w, GdkEventWindowState *event){
-        if ((event->new_window_state & GDK_WINDOW_STATE_ICONIFIED) ||(event->new_window_state & GDK_WINDOW_STATE_WITHDRAWN) ){
-                linphone_core_enable_video_preview(linphone_gtk_get_core(),FALSE);
-        }else{
-                linphone_core_enable_video_preview(linphone_gtk_get_core(),
-               linphone_gtk_get_ui_config_int("videoselfview",VIDEOSELFVIEW_DEFAULT) && linphone_core_video_enabled(linphone_gtk_get_core()));
-        }
-        return FALSE;
+       bool_t video_enabled=linphone_gtk_video_enabled();
+       if ((event->new_window_state & GDK_WINDOW_STATE_ICONIFIED) ||(event->new_window_state & GDK_WINDOW_STATE_WITHDRAWN) ){
+               linphone_core_enable_video_preview(linphone_gtk_get_core(),FALSE);
+       }else{
+               linphone_core_enable_video_preview(linphone_gtk_get_core(),
+               linphone_gtk_get_ui_config_int("videoselfview",VIDEOSELFVIEW_DEFAULT) && video_enabled);
+       }
+       return FALSE;
 }
 #endif
 
+void linphone_gtk_init_dtmf_table(GtkWidget *mw){
+       GtkWidget *dtmf_table=linphone_gtk_get_widget(mw,"dtmf_table");
+       gtk_widget_set_direction(dtmf_table, GTK_TEXT_DIR_LTR);
+
+       g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_A")),"label","A");
+       g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_B")),"label","B");
+       g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_C")),"label","C");
+       g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_D")),"label","D");
+       g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_1")),"label","1");
+       g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_2")),"label","2");
+       g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_3")),"label","3");
+       g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_4")),"label","4");
+       g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_5")),"label","5");
+       g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_6")),"label","6");
+       g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_7")),"label","7");
+       g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_8")),"label","8");
+       g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_9")),"label","9");
+       g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_0")),"label","0");
+       g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_#")),"label","#");
+       g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_*")),"label","*");
+}
+
+void linphone_gtk_create_keypad(GtkWidget *button){
+       GtkWidget *mw=linphone_gtk_get_main_window();
+       GtkWidget *k=(GtkWidget *)g_object_get_data(G_OBJECT(mw),"keypad");
+       if(k!=NULL){
+               gtk_widget_destroy(k);
+       }
+       GtkWidget *keypad=linphone_gtk_create_window("keypad");
+       linphone_gtk_connect_digits(keypad);
+       linphone_gtk_init_dtmf_table(keypad);
+       g_object_set_data(G_OBJECT(mw),"keypad",(gpointer)keypad);
+       if(!GPOINTER_TO_INT(g_object_get_data(G_OBJECT(mw),"show_abcd"))){
+               gtk_widget_hide(linphone_gtk_get_widget(keypad,"dtmf_A"));
+               gtk_widget_hide(linphone_gtk_get_widget(keypad,"dtmf_B"));
+               gtk_widget_hide(linphone_gtk_get_widget(keypad,"dtmf_C"));
+               gtk_widget_hide(linphone_gtk_get_widget(keypad,"dtmf_D"));
+               gtk_table_resize(GTK_TABLE(linphone_gtk_get_widget(keypad,"dtmf_table")),4,3);
+       }
+       gtk_widget_show(keypad);
+}
 
 static void linphone_gtk_init_main_window(){
        GtkWidget *main_window;
-
        linphone_gtk_configure_main_window();
        linphone_gtk_manage_login();
        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_core_reset_missed_calls_count(linphone_gtk_get_core());
        main_window=linphone_gtk_get_main_window();
        linphone_gtk_call_log_update(main_window);
-       
+
        linphone_gtk_update_call_buttons (NULL);
+       g_object_set_data(G_OBJECT(main_window),"keypad",NULL);
+       g_object_set_data(G_OBJECT(main_window),"is_conf",GINT_TO_POINTER(FALSE));
        /*prevent the main window from being destroyed by a user click on WM controls, instead we hide it*/
        g_signal_connect (G_OBJECT (main_window), "delete-event",
                G_CALLBACK (linphone_gtk_close), main_window);
 #ifdef HAVE_GTK_OSX
        {
                GtkWidget *menubar=linphone_gtk_get_widget(main_window,"menubar1");
-               GtkOSXApplication *theMacApp = (GtkOSXApplication*)g_object_new(GTK_TYPE_OSX_APPLICATION, NULL);
-               gtk_osxapplication_set_menu_bar(theMacApp,GTK_MENU_SHELL(menubar));
+               GtkosxApplication *theMacApp = gtkosx_application_get();
+               gtkosx_application_set_menu_bar(theMacApp,GTK_MENU_SHELL(menubar));
                gtk_widget_hide(menubar);
-               gtk_osxapplication_ready(theMacApp);
+               gtkosx_application_ready(theMacApp);
        }
        g_signal_connect(G_OBJECT(main_window), "window-state-event",G_CALLBACK(on_window_state_event), NULL);
 #endif
        linphone_gtk_check_menu_items();
 }
 
-
 void linphone_gtk_log_handler(OrtpLogLevel lev, const char *fmt, va_list args){
        if (verbose){
                const char *lname="undef";
@@ -1501,14 +1809,23 @@ static void linphone_gtk_check_soundcards(){
 }
 
 static void linphone_gtk_quit(void){
-       linphone_gtk_uninit_instance();
-       gdk_threads_leave();
-       linphone_gtk_destroy_log_window();
-       linphone_core_destroy(the_core);
-       linphone_gtk_log_uninit();
+       static gboolean quit_done=FALSE;
+       if (!quit_done){
+               quit_done=TRUE;
+               linphone_gtk_unmonitor_usb();
+               g_source_remove_by_user_data(linphone_gtk_get_core());
+#ifdef BUILD_WIZARD
+               linphone_gtk_close_assistant();
+#endif
+               linphone_gtk_uninit_instance();
+               linphone_gtk_destroy_log_window();
+               linphone_core_destroy(the_core);
+               linphone_gtk_log_uninit();
 #ifdef HAVE_NOTIFY
-       notify_uninit();
+               notify_uninit();
 #endif
+               gdk_threads_leave();
+       }
 }
 
 #ifdef HAVE_GTK_OSX
@@ -1530,20 +1847,24 @@ int main(int argc, char *argv[]){
 #ifdef ENABLE_NLS
        void *p;
 #endif
-       const char *config_file;
+       char *config_file;
        const char *factory_config_file;
        const char *lang;
        GtkSettings *settings;
        GdkPixbuf *pbuf;
        const char *app_name="Linphone";
+       LpConfig *factory;
+       const char *db_file;
 
+#if !GLIB_CHECK_VERSION(2, 31, 0)
        g_thread_init(NULL);
+#endif
        gdk_threads_init();
-       
+
        progpath = strdup(argv[0]);
-       
-       config_file=linphone_gtk_get_config_file();
-       
+
+       config_file=linphone_gtk_get_config_file(NULL);
+
 
 #ifdef WIN32
        /*workaround for windows: sometimes LANG is defined to an integer value, not understood by gtk */
@@ -1564,8 +1885,13 @@ int main(int argc, char *argv[]){
                char tmp[128];
                snprintf(tmp,sizeof(tmp),"LANG=%s",lang);
                _putenv(tmp);
-#else
+               if (strncmp(lang,"zh",2)==0){
+                       workaround_gtk_entry_chinese_bug=TRUE;
+               }
+#elif __APPLE__
                setenv("LANG",lang,1);
+#else
+               setenv("LANGUAGE",lang,1);
 #endif
        }
 
@@ -1581,13 +1907,13 @@ int main(int argc, char *argv[]){
        gtk_rc_add_default_file("./gtkrc");
 #endif
        gdk_threads_enter();
-       
+
        if (!gtk_init_with_args(&argc,&argv,_("A free SIP video-phone"),
                                linphone_options,NULL,NULL)){
                gdk_threads_leave();
                return -1;
        }
-       
+
        settings=gtk_settings_get_default();
        g_type_class_unref (g_type_class_ref (GTK_TYPE_IMAGE_MENU_ITEM));
        g_type_class_unref (g_type_class_ref (GTK_TYPE_BUTTON));
@@ -1604,6 +1930,11 @@ int main(int argc, char *argv[]){
                 since we want to have had time to change directory and to parse
                 the options, in case we needed to access the working directory */
        factory_config_file = linphone_gtk_get_factory_config_file();
+       if (factory_config_file){
+               factory=lp_config_new(NULL);
+               lp_config_read_file(factory,factory_config_file);
+               app_name=lp_config_get_string(factory,"GtkUi","title","Linphone");
+       }
 
        if (linphone_gtk_init_instance(app_name, addr_to_call) == FALSE){
                g_warning("Another running instance of linphone has been detected. It has been woken-up.");
@@ -1616,28 +1947,39 @@ int main(int argc, char *argv[]){
        add_pixmap_directory(PACKAGE_DATA_DIR "/pixmaps/linphone");
 
 #ifdef HAVE_GTK_OSX
-       GtkOSXApplication *theMacApp = (GtkOSXApplication*)g_object_new(GTK_TYPE_OSX_APPLICATION, NULL);
+       GtkosxApplication *theMacApp = gtkosx_application_get();
        g_signal_connect(G_OBJECT(theMacApp),"NSApplicationDidBecomeActive",(GCallback)linphone_gtk_show_main_window,NULL);
        g_signal_connect(G_OBJECT(theMacApp),"NSApplicationWillTerminate",(GCallback)gtk_main_quit,NULL);
        /*never block termination:*/
        g_signal_connect(G_OBJECT(theMacApp),"NSApplicationBlockTermination",(GCallback)on_block_termination,NULL);
 #endif
-       
+
        the_ui=linphone_gtk_create_window("main");
-       
+
+       g_object_set_data(G_OBJECT(the_ui),"is_created",GINT_TO_POINTER(FALSE));
+
        linphone_gtk_create_log_window();
        linphone_core_enable_logs_with_cb(linphone_gtk_log_handler);
 
-       linphone_gtk_init_liblinphone(config_file, factory_config_file);
-       
+       db_file=linphone_gtk_message_storage_get_db_file(NULL);
+       linphone_gtk_init_liblinphone(config_file, factory_config_file, db_file);
+
        g_set_application_name(app_name);
        pbuf=create_pixbuf(linphone_gtk_get_ui_config("icon",LINPHONE_ICON));
        if (pbuf!=NULL) gtk_window_set_default_icon(pbuf);
-       
+
        /* do not lower timeouts under 30 ms because it exhibits a bug on gtk+/win32, with cpu running 20% all the time...*/
        gtk_timeout_add(30,(GtkFunction)linphone_gtk_iterate,(gpointer)linphone_gtk_get_core());
        gtk_timeout_add(30,(GtkFunction)linphone_gtk_check_logs,(gpointer)NULL);
        linphone_gtk_init_main_window();
+
+#ifdef BUILD_WIZARD
+       // Veryfing if at least one sip account is configured. If not, show wizard
+       if (linphone_core_get_proxy_config_list(linphone_gtk_get_core()) == NULL) {
+               linphone_gtk_show_assistant();
+       }
+#endif
+
 #ifndef HAVE_GTK_OSX
        linphone_gtk_init_status_icon();
 #endif
@@ -1647,6 +1989,7 @@ int main(int argc, char *argv[]){
        }
        if (linphone_gtk_get_ui_config_int("update_check_menu",0)==0)
                linphone_gtk_check_for_new_version();
+       linphone_gtk_monitor_usb();
 
        gtk_main();
        linphone_gtk_quit();