source: mediastreamer2/linphone/gtk-glade/main.c @ 437:7223a5d0e4c2

Last change on this file since 437:7223a5d0e4c2 was 437:7223a5d0e4c2, checked in by smorlat <smorlat@…>, 4 years ago

add evrcb0
wizard in progress
improve theora packer
add \n to dtmf printout.

git-svn-id: svn+ssh://svn.savannah.nongnu.org/linphone/trunk@440 3f6dc0c8-ddfe-455d-9043-3cd528dc4637

File size: 31.8 KB
Line 
1/*
2linphone, gtk-glade interface.
3Copyright (C) 2008  Simon MORLAT (simon.morlat@linphone.org)
4
5This program is free software; you can redistribute it and/or
6modify it under the terms of the GNU General Public License
7as published by the Free Software Foundation; either version 2
8of the License, or (at your option) any later version.
9
10This program is distributed in the hope that it will be useful,
11but WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18*/
19
20#define USE_LIBGLADE 1
21
22#include "lpconfig.h"
23
24#include "linphone.h"
25
26#ifdef USE_LIBGLADE
27#include <glade/glade.h>
28#endif
29
30#include <sys/types.h>
31#include <sys/stat.h>
32#include <unistd.h>
33
34#ifndef GETTEXT_PACKAGE
35#define GETTEXT_PACKAGE "linphone"
36#endif
37
38#ifndef PACKAGE_LOCALE_DIR
39#define PACKAGE_LOCALE_DIR "share/locale/"
40#endif
41
42#define LINPHONE_ICON "linphone2.png"
43
44const char *this_program_ident_string="linphone_ident_string=" LINPHONE_VERSION;
45
46static LinphoneCore *the_core=NULL;
47static GtkWidget *the_ui=NULL;
48
49static void linphone_gtk_show(LinphoneCore *lc);
50static void linphone_gtk_inv_recv(LinphoneCore *lc, const char *from);
51static void linphone_gtk_bye_recv(LinphoneCore *lc, const char *from);
52static void linphone_gtk_notify_recv(LinphoneCore *lc, LinphoneFriend * fid, const char *url, const char *status, const char *img);
53static void linphone_gtk_new_unknown_subscriber(LinphoneCore *lc, LinphoneFriend *lf, const char *url);
54static void linphone_gtk_auth_info_requested(LinphoneCore *lc, const char *realm, const char *username);
55static void linphone_gtk_display_status(LinphoneCore *lc, const char *status);
56static void linphone_gtk_display_message(LinphoneCore *lc, const char *msg);
57static void linphone_gtk_display_warning(LinphoneCore *lc, const char *warning);
58static void linphone_gtk_display_url(LinphoneCore *lc, const char *msg, const char *url);
59static void linphone_gtk_display_question(LinphoneCore *lc, const char *question);
60static void linphone_gtk_call_log_updated(LinphoneCore *lc, LinphoneCallLog *cl);
61static void linphone_gtk_general_state(LinphoneCore *lc, LinphoneGeneralState *gstate);
62
63static LinphoneCoreVTable vtable={
64        .show=linphone_gtk_show,
65        .inv_recv=linphone_gtk_inv_recv,
66        .bye_recv=linphone_gtk_bye_recv,
67        .notify_recv=linphone_gtk_notify_recv,
68        .new_unknown_subscriber=linphone_gtk_new_unknown_subscriber,
69        .auth_info_requested=linphone_gtk_auth_info_requested,
70        .display_status=linphone_gtk_display_status,
71        .display_message=linphone_gtk_display_message,
72        .display_warning=linphone_gtk_display_warning,
73        .display_url=linphone_gtk_display_url,
74        .display_question=linphone_gtk_display_question,
75        .call_log_updated=linphone_gtk_call_log_updated,
76        .text_received=linphone_gtk_text_received,
77        .general_state=linphone_gtk_general_state,
78        .waiting=linphone_gtk_wait
79};
80
81static gboolean verbose=0;
82static GOptionEntry linphone_options[2]={
83        {
84                .long_name="verbose",
85                .short_name= '\0',
86                .arg=G_OPTION_ARG_NONE,
87                .arg_data= (gpointer)&verbose,
88                .description="log to stdout some debug information while running."
89        }
90};
91
92#define INSTALLED_XML_DIR PACKAGE_DATA_DIR "/linphone"
93#define BUILD_TREE_XML_DIR "gtk-glade"
94#define CONFIG_FILE ".linphonerc"
95
96static char _config_file[1024];
97
98const char *linphone_gtk_get_config_file(){
99        const char *home;
100        /*try accessing a local file first if exists*/
101        if (access(CONFIG_FILE,F_OK)==0){
102                snprintf(_config_file,sizeof(_config_file),"%s",CONFIG_FILE);
103        }else{
104#ifdef WIN32
105                const char *appdata=getenv("APPDATA");
106                if (appdata){
107                        snprintf(_config_file,sizeof(_config_file),"%s\\%s",appdata,"Linphone\\");
108                        CreateDirectory(_config_file,NULL);
109                        snprintf(_config_file,sizeof(_config_file),"%s\\%s",appdata,"Linphone\\linphonerc");
110                }
111#else
112                home=getenv("HOME");
113                if (home==NULL) home="";
114                snprintf(_config_file,sizeof(_config_file),"%s/%s",home,CONFIG_FILE);
115#endif
116        }
117        return _config_file;
118}
119
120static void linphone_gtk_init_liblinphone(const char *file){
121        linphone_core_set_user_agent("Linphone", LINPHONE_VERSION);
122        the_core=linphone_core_new(&vtable,file,NULL);
123}
124
125
126
127LinphoneCore *linphone_gtk_get_core(void){
128        return the_core;
129}
130
131GtkWidget *linphone_gtk_get_main_window(){
132        return the_ui;
133}
134
135static void parse_item(const char *item, const char *window_name, GtkWidget *w){
136        char tmp[64];
137        char *dot;
138        strcpy(tmp,item);
139        dot=strchr(tmp,'.');
140        if (dot){
141                *dot='\0';
142                dot++;
143                if (strcmp(window_name,tmp)==0){
144                        GtkWidget *wd=linphone_gtk_get_widget(w,dot);
145                        if (wd) gtk_widget_hide(wd);
146                }
147        }
148}
149
150static void parse_hiddens(const char *hiddens, const char *window_name, GtkWidget *w){
151        char item[64];
152        const char *i;
153        const char *b;
154        int len;
155        for(b=i=hiddens;*i!='\0';++i){
156                if (*i==' '){
157                        len=MIN(i-b,sizeof(item)-1);
158                        strncpy(item,b,len);
159                        item[len]='\0';
160                        b=i+1;
161                        parse_item(item,window_name,w);
162                }
163        }
164        len=MIN(i-b,sizeof(item)-1);
165        if (len>0){
166                strncpy(item,b,len);
167                item[len]='\0';
168                parse_item(item,window_name,w);
169        }
170}
171
172static void linphone_gtk_configure_window(GtkWidget *w, const char *window_name){
173        static const char *icon_path=0;
174        static const char *hiddens=0;
175        static bool_t config_loaded=FALSE;
176        if (linphone_gtk_get_core()==NULL) return;
177        if (config_loaded==FALSE){
178                hiddens=linphone_gtk_get_ui_config("hidden_widgets",NULL);
179                icon_path=linphone_gtk_get_ui_config("icon",NULL);
180                config_loaded=TRUE;
181        }
182        if (hiddens){
183                parse_hiddens(hiddens,window_name,w);
184        }
185        if (icon_path) {
186                GdkPixbuf *pbuf=create_pixbuf(icon_path);
187                gtk_window_set_icon(GTK_WINDOW(w),pbuf);
188                g_object_unref(G_OBJECT(pbuf));
189        }
190}
191
192#ifdef USE_LIBGLADE
193
194GtkWidget *linphone_gtk_create_window(const char *window_name){
195        GtkWidget *w;
196        GladeXML *gxml;
197        char path[2048];
198        snprintf(path,sizeof(path),"%s/%s.glade",BUILD_TREE_XML_DIR,window_name);
199        if (access(path,F_OK)!=0){
200                snprintf(path,sizeof(path),"%s/%s.glade",INSTALLED_XML_DIR,window_name);
201                if (access(path,F_OK)!=0){
202                        g_error("Could not locate neither %s/%s.glade and %s/%s.glade .",BUILD_TREE_XML_DIR,window_name,
203                                INSTALLED_XML_DIR,window_name);
204                        return NULL;
205                }
206        }
207        gxml=glade_xml_new(path,NULL,NULL);
208        glade_xml_signal_autoconnect(gxml);
209        w=glade_xml_get_widget(gxml,window_name);
210        if (w==NULL) g_error("Could not retrieve '%s' window from xml file",window_name);
211        linphone_gtk_configure_window(w,window_name);
212        return w;
213}
214
215GtkWidget *linphone_gtk_get_widget(GtkWidget *window, const char *name){
216        GtkWidget *w;
217        GladeXML *gxml=glade_get_widget_tree(window);
218        if (gxml==NULL) g_error("Could not retrieve XML tree of window %s",name);
219        w=glade_xml_get_widget(gxml,name);
220        if (w==NULL) g_error("Could not retrieve widget %s",name);
221        return GTK_WIDGET(w);
222}
223
224#else
225
226GtkWidget *linphone_gtk_create_window(const char *window_name){
227       
228}
229
230GtkWidget *linphone_gtk_get_widget(GtkWidget *window, const char *name){
231        GObject *w=gtk_builder_get_object(the_ui,name);
232        if (w==NULL){
233                g_error("No widget named %s found in xml interface.",name);
234        }
235        return GTK_WIDGET(w);
236}
237
238#endif
239
240void linphone_gtk_display_something(GtkMessageType type,const gchar *message){
241        GtkWidget *dialog;
242        GtkWidget *main_window=linphone_gtk_get_main_window();
243       
244        gtk_widget_show(main_window);
245        if (type==GTK_MESSAGE_QUESTION)
246        {
247                /* draw a question box. link to dialog_click callback */
248                dialog = gtk_message_dialog_new (
249                                GTK_WINDOW(main_window),
250                                GTK_DIALOG_DESTROY_WITH_PARENT,
251                                GTK_MESSAGE_QUESTION,
252                                GTK_BUTTONS_YES_NO,
253                                "%s",
254                                (const gchar*)message);
255                /* connect to some callback : REVISIT */
256                /*
257                g_signal_connect_swapped (G_OBJECT (dialog), "response",
258                           G_CALLBACK (dialog_click),
259                           G_OBJECT (dialog));
260                */
261                /* actually show the box */
262                gtk_widget_show(dialog);
263        }
264        else
265        {
266                dialog = gtk_message_dialog_new (GTK_WINDOW(main_window),
267                                  GTK_DIALOG_DESTROY_WITH_PARENT,
268                                  type,
269                                  GTK_BUTTONS_CLOSE,
270                                  "%s",
271                                  (const gchar*)message);
272                /* Destroy the dialog when the user responds to it (e.g. clicks a button) */
273                g_signal_connect_swapped (G_OBJECT (dialog), "response",
274                           G_CALLBACK (gtk_widget_destroy),
275                           G_OBJECT (dialog));
276                gtk_widget_show(dialog);
277        }
278}
279
280void linphone_gtk_about_response(GtkDialog *dialog, gint id){
281        if (id==GTK_RESPONSE_CANCEL){
282                gtk_widget_destroy(GTK_WIDGET(dialog));
283        }
284}
285
286void linphone_gtk_show_about(){
287        struct stat filestat;
288        const char *license_file=PACKAGE_DATA_DIR "/doc/COPYING";
289        GtkWidget *about;
290
291        about=linphone_gtk_create_window("about");
292        memset(&filestat,0,sizeof(filestat));
293        if (stat(license_file,&filestat)!=0){
294                license_file="COPYING";
295                stat(license_file,&filestat);
296        }
297        if (filestat.st_size>0){
298                char *license=g_malloc(filestat.st_size+1);
299                FILE *f=fopen(license_file,"r");
300                if (f && fread(license,filestat.st_size,1,f)==1){
301                        license[filestat.st_size]='\0';
302                        gtk_about_dialog_set_license(GTK_ABOUT_DIALOG(about),license);
303                }
304                g_free(license);
305        }
306        gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(about),LINPHONE_VERSION);
307
308        gtk_widget_show(about);
309}
310
311static void set_video_window_decorations(GdkWindow *w){
312        const char *title=linphone_gtk_get_ui_config("title","Linphone");
313        const char *icon_path=linphone_gtk_get_ui_config("icon","linphone2.png");
314        char video_title[256];
315        GdkPixbuf *pbuf=create_pixbuf(icon_path);
316        snprintf(video_title,sizeof(video_title),"%s video",title);
317        gdk_window_set_title(w,video_title);
318        if (pbuf){
319                GList *l=NULL;
320                l=g_list_append(l,pbuf);
321                gdk_window_set_icon_list(w,l);
322                g_list_free(l);
323                g_object_unref(G_OBJECT(pbuf));
324        }
325}
326
327
328static gboolean linphone_gtk_iterate(LinphoneCore *lc){
329        unsigned long id;
330        static unsigned long previd=0;
331        static gboolean in_iterate=FALSE;
332       
333        /*avoid reentrancy*/
334        if (in_iterate) return TRUE;
335        in_iterate=TRUE;
336        linphone_core_iterate(lc);
337        id=linphone_core_get_native_video_window_id(lc);
338        if (id!=previd){
339                ms_message("Updating window decorations");
340                GdkWindow *w;
341                previd=id;
342                if (id!=0){
343                        w=gdk_window_foreign_new(id);
344                        if (w) {
345                                set_video_window_decorations(w);
346                                g_object_unref(G_OBJECT(w));
347                        }
348                        else ms_error("gdk_window_foreign_new() failed");
349                }
350        }
351        in_iterate=FALSE;
352        return TRUE;
353}
354
355static void load_uri_history(){
356        GtkEntry *uribar=GTK_ENTRY(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"uribar"));
357        char key[20];
358        int i;
359        GtkEntryCompletion *gep=gtk_entry_completion_new();
360        GtkListStore *model=gtk_list_store_new(1,G_TYPE_STRING);
361        for (i=0;;i++){
362                const char *uri;
363                snprintf(key,sizeof(key),"uri%i",i);
364                uri=linphone_gtk_get_ui_config(key,NULL);
365                if (uri!=NULL) {
366                        GtkTreeIter iter;
367                        gtk_list_store_append(model,&iter);
368                        gtk_list_store_set(model,&iter,0,uri,-1);
369                        if (i==0) gtk_entry_set_text(uribar,uri);
370                }
371                else break;
372        }
373        gtk_entry_completion_set_model(gep,GTK_TREE_MODEL(model));
374        gtk_entry_completion_set_text_column(gep,0);
375        gtk_entry_set_completion(uribar,gep);
376}
377
378static void save_uri_history(){
379        LinphoneCore *lc=linphone_gtk_get_core();
380        LpConfig *cfg=linphone_core_get_config(lc);
381        GtkEntry *uribar=GTK_ENTRY(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"uribar"));
382        char key[20];
383        int i=0;
384        char *uri=NULL;
385        GtkTreeIter iter;
386        GtkTreeModel *model=gtk_entry_completion_get_model(gtk_entry_get_completion(uribar));
387
388        if (!gtk_tree_model_get_iter_first(model,&iter)) return;
389        do {
390                gtk_tree_model_get(model,&iter,0,&uri,-1);
391                if (uri) {
392                        snprintf(key,sizeof(key),"uri%i",i);
393                        lp_config_set_string(cfg,"GtkUi",key,uri);
394                        g_free(uri);
395                }else break;
396                i++;
397                if (i>5) break;
398        }while(gtk_tree_model_iter_next(model,&iter));
399        lp_config_sync(cfg);
400}
401
402static void completion_add_text(GtkEntry *entry, const char *text){
403        GtkTreeIter iter;
404        GtkTreeModel *model=gtk_entry_completion_get_model(gtk_entry_get_completion(entry));
405       
406        if (gtk_tree_model_get_iter_first(model,&iter)){ 
407                do {
408                        gchar *uri=NULL;
409                        gtk_tree_model_get(model,&iter,0,&uri,-1);
410                        if (uri!=NULL){
411                                if (strcmp(uri,text)==0) {
412                                        /*remove text */
413                                        gtk_list_store_remove(GTK_LIST_STORE(model),&iter);
414                                        g_free(uri);
415                                        break;
416                                }
417                                g_free(uri);
418                        }
419                }while (gtk_tree_model_iter_next(model,&iter));
420        }
421        /* and prepend it on top of the list */
422        gtk_list_store_prepend(GTK_LIST_STORE(model),&iter);
423        gtk_list_store_set(GTK_LIST_STORE(model),&iter,0,text,-1);
424        save_uri_history();
425}
426
427static void linphone_gtk_call_terminated(GtkWidget *mw){
428        gtk_widget_hide(linphone_gtk_get_widget(mw,"terminate_call"));
429        gtk_widget_show(linphone_gtk_get_widget(mw,"start_call"));
430        g_object_set_data(G_OBJECT(mw),"incoming_call",NULL);
431}
432
433gboolean check_call_active(){
434        if (!linphone_core_in_call(linphone_gtk_get_core())){
435                linphone_gtk_call_terminated(linphone_gtk_get_main_window());
436                return FALSE;
437        }
438        return TRUE;
439}
440
441static void linphone_gtk_call_started(GtkWidget *mw){
442        gtk_widget_hide(linphone_gtk_get_widget(mw,"start_call"));
443        gtk_widget_show(linphone_gtk_get_widget(mw,"terminate_call"));
444        g_timeout_add(250,(GSourceFunc)check_call_active,NULL);
445}
446
447void linphone_gtk_start_call(GtkWidget *w){
448        LinphoneCore *lc=linphone_gtk_get_core();
449        if (linphone_core_inc_invite_pending(lc)){
450                /*already in call */
451        }else{
452                GtkWidget *uri_bar=linphone_gtk_get_widget(gtk_widget_get_toplevel(w),"uribar");
453                const char *entered=gtk_entry_get_text(GTK_ENTRY(uri_bar));
454                if (linphone_core_invite(lc,entered)==0) {
455                        linphone_gtk_call_started(linphone_gtk_get_main_window());
456                        completion_add_text(GTK_ENTRY(uri_bar),entered);
457                }
458        }
459}
460
461void linphone_gtk_uri_bar_activate(GtkWidget *w){
462        linphone_gtk_start_call(w);
463}
464
465
466void linphone_gtk_terminate_call(GtkWidget *button){
467        linphone_core_terminate_call(linphone_gtk_get_core(),NULL);
468        linphone_gtk_call_terminated(gtk_widget_get_toplevel(button));
469}
470
471void linphone_gtk_decline_call(GtkWidget *button){
472        linphone_core_terminate_call(linphone_gtk_get_core(),NULL);
473        linphone_gtk_call_terminated(linphone_gtk_get_main_window());
474        gtk_widget_destroy(gtk_widget_get_toplevel(button));
475}
476
477void linphone_gtk_accept_call(GtkWidget *button){
478        linphone_core_accept_call(linphone_gtk_get_core(),NULL);
479        g_object_set_data(G_OBJECT(linphone_gtk_get_main_window()),"incoming_call",NULL);
480        gtk_widget_destroy(gtk_widget_get_toplevel(button));
481        linphone_gtk_call_started(linphone_gtk_get_main_window());
482}
483
484void linphone_gtk_set_audio_video(){
485        linphone_core_enable_video(linphone_gtk_get_core(),TRUE,TRUE);
486        linphone_core_enable_video_preview(linphone_gtk_get_core(),TRUE);
487}
488
489void linphone_gtk_set_audio_only(){
490        linphone_core_enable_video(linphone_gtk_get_core(),FALSE,FALSE);
491        linphone_core_enable_video_preview(linphone_gtk_get_core(),FALSE);
492}
493
494void linphone_gtk_enable_self_view(GtkWidget *w){
495        linphone_core_enable_self_view(linphone_gtk_get_core(),
496                gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w)));
497}
498
499void linphone_gtk_used_identity_changed(GtkWidget *w){
500        int active=gtk_combo_box_get_active(GTK_COMBO_BOX(w));
501        char *sel=gtk_combo_box_get_active_text(GTK_COMBO_BOX(w));
502        if (sel && strlen(sel)>0) //avoid a dummy "changed" at gui startup
503                linphone_core_set_default_proxy_index(linphone_gtk_get_core(),(active==0) ? -1 : (active-1));
504}
505
506static void linphone_gtk_show_main_window(){
507        GtkWidget *w=linphone_gtk_get_main_window();
508        LinphoneCore *lc=linphone_gtk_get_core();
509        linphone_core_enable_video_preview(lc,linphone_core_video_enabled(lc));
510        gtk_widget_show(w);
511        gtk_window_present(GTK_WINDOW(w));
512}
513
514static void linphone_gtk_show(LinphoneCore *lc){
515        linphone_gtk_show_main_window();
516}
517
518static void linphone_gtk_inv_recv(LinphoneCore *lc, const char *from){
519        GtkWidget *w=linphone_gtk_create_window("incoming_call");
520        GtkWidget *label;
521        gchar *msg;
522        gtk_window_set_transient_for(GTK_WINDOW(w),GTK_WINDOW(linphone_gtk_get_main_window()));
523        gtk_window_set_position(GTK_WINDOW(w),GTK_WIN_POS_CENTER_ON_PARENT);
524
525        label=linphone_gtk_get_widget(w,"message");
526        msg=g_strdup_printf(_("Incoming call from %s"),from);
527        gtk_label_set_text(GTK_LABEL(label),msg);
528        gtk_window_set_title(GTK_WINDOW(w),msg);
529        gtk_widget_show(w);
530        gtk_window_present(GTK_WINDOW(w));
531        /*gtk_window_set_urgency_hint(GTK_WINDOW(w),TRUE);*/
532        g_free(msg);
533        g_object_set_data(G_OBJECT(linphone_gtk_get_main_window()),"incoming_call",w);
534        gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"uribar")),
535                        from);
536}
537
538static void linphone_gtk_bye_recv(LinphoneCore *lc, const char *from){
539        GtkWidget *icw=GTK_WIDGET(g_object_get_data(G_OBJECT(linphone_gtk_get_main_window()),"incoming_call"));
540        if (icw!=NULL){
541                gtk_widget_destroy(icw);
542        }
543        linphone_gtk_call_terminated(linphone_gtk_get_main_window());
544}
545
546static void linphone_gtk_notify_recv(LinphoneCore *lc, LinphoneFriend * fid, const char *url, const char *status, const char *img){
547}
548
549static void linphone_gtk_new_subscriber_response(GtkWidget *dialog, guint response_id, LinphoneFriend *lf){
550        switch(response_id){
551                case GTK_RESPONSE_YES:
552                        linphone_gtk_show_contact(lf);
553                break;
554                default:
555                        linphone_core_reject_subscriber(linphone_gtk_get_core(),lf);
556        }
557        gtk_widget_destroy(dialog);
558}
559
560static void linphone_gtk_new_unknown_subscriber(LinphoneCore *lc, LinphoneFriend *lf, const char *url){
561        GtkWidget *dialog;
562        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);
563        dialog = gtk_message_dialog_new (
564                                GTK_WINDOW(linphone_gtk_get_main_window()),
565                                GTK_DIALOG_DESTROY_WITH_PARENT,
566                                GTK_MESSAGE_QUESTION,
567                                GTK_BUTTONS_YES_NO,
568                                "%s",
569                                message);
570        g_free(message);
571        g_signal_connect(G_OBJECT (dialog), "response",
572                G_CALLBACK (linphone_gtk_new_subscriber_response),lf);
573        /* actually show the box */
574        gtk_widget_show(dialog);
575}
576
577typedef struct _AuthTimeout{
578        GtkWidget *w;
579} AuthTimeout;
580
581
582static void auth_timeout_clean(AuthTimeout *tout){
583        tout->w=NULL;
584}
585
586static gboolean auth_timeout_destroy(AuthTimeout *tout){
587        if (tout->w)  {
588                g_object_weak_unref(G_OBJECT(tout->w),(GWeakNotify)auth_timeout_clean,tout);
589                gtk_widget_destroy(tout->w);
590        }
591        g_free(tout);
592        return FALSE;
593}
594
595static AuthTimeout * auth_timeout_new(GtkWidget *w){
596        AuthTimeout *tout=g_new(AuthTimeout,1);
597        tout->w=w;
598        /*so that the timeout no more references the widget when it is destroyed:*/
599        g_object_weak_ref(G_OBJECT(w),(GWeakNotify)auth_timeout_clean,tout);
600        /*so that the widget is automatically destroyed after some time */
601        g_timeout_add(30000,(GtkFunction)auth_timeout_destroy,tout);
602        return tout;
603}
604
605void linphone_gtk_password_cancel(GtkWidget *w){
606        LinphoneAuthInfo *info;
607        GtkWidget *window=gtk_widget_get_toplevel(w);
608        info=(LinphoneAuthInfo*)g_object_get_data(G_OBJECT(window),"auth_info");
609        linphone_core_abort_authentication(linphone_gtk_get_core(),info);
610        gtk_widget_destroy(window);
611}
612
613void linphone_gtk_password_ok(GtkWidget *w){
614        GtkWidget *entry;
615        GtkWidget *window=gtk_widget_get_toplevel(w);
616        LinphoneAuthInfo *info;
617        info=(LinphoneAuthInfo*)g_object_get_data(G_OBJECT(window),"auth_info");
618        g_object_weak_unref(G_OBJECT(window),(GWeakNotify)linphone_auth_info_destroy,info);
619        entry=linphone_gtk_get_widget(window,"password_entry");
620        linphone_auth_info_set_passwd(info,gtk_entry_get_text(GTK_ENTRY(entry)));
621        linphone_auth_info_set_username(info,
622                gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(window,"username_entry"))));
623        linphone_core_add_auth_info(linphone_gtk_get_core(),info);
624        gtk_widget_destroy(window);
625}
626
627static void linphone_gtk_auth_info_requested(LinphoneCore *lc, const char *realm, const char *username){
628        GtkWidget *w=linphone_gtk_create_window("password");
629        GtkWidget *label=linphone_gtk_get_widget(w,"message");
630        LinphoneAuthInfo *info;
631        gchar *msg;
632        msg=g_strdup_printf(_("Please enter your password for domain %s:"),realm);
633        gtk_label_set_text(GTK_LABEL(label),msg);
634        g_free(msg);
635        gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(w,"username_entry")),username);
636        info=linphone_auth_info_new(username, NULL, NULL, NULL,realm);
637        g_object_set_data(G_OBJECT(w),"auth_info",info);
638        g_object_weak_ref(G_OBJECT(w),(GWeakNotify)linphone_auth_info_destroy,info);
639        gtk_widget_show(w);
640        auth_timeout_new(w);
641}
642
643static void linphone_gtk_display_status(LinphoneCore *lc, const char *status){
644        GtkWidget *w=linphone_gtk_get_main_window();
645        GtkWidget *status_bar=linphone_gtk_get_widget(w,"status_bar");
646        gtk_statusbar_push(GTK_STATUSBAR(status_bar),
647                        gtk_statusbar_get_context_id(GTK_STATUSBAR(status_bar),""),
648                        status);
649}
650
651static void linphone_gtk_display_message(LinphoneCore *lc, const char *msg){
652        linphone_gtk_display_something(GTK_MESSAGE_INFO,msg);
653}
654
655static void linphone_gtk_display_warning(LinphoneCore *lc, const char *warning){
656        linphone_gtk_display_something(GTK_MESSAGE_WARNING,warning);
657}
658
659static void linphone_gtk_display_url(LinphoneCore *lc, const char *msg, const char *url){
660        char richtext[4096];
661        snprintf(richtext,sizeof(richtext),"%s %s",msg,url);
662        linphone_gtk_display_something(GTK_MESSAGE_INFO,richtext);
663}
664
665static void linphone_gtk_display_question(LinphoneCore *lc, const char *question){
666        linphone_gtk_display_something(GTK_MESSAGE_QUESTION,question);
667}
668
669static void linphone_gtk_call_log_updated(LinphoneCore *lc, LinphoneCallLog *cl){
670        GtkWidget *w=(GtkWidget*)g_object_get_data(G_OBJECT(linphone_gtk_get_main_window()),"call_logs");
671        if (w) linphone_gtk_call_log_update(w);
672}
673
674static void linphone_gtk_general_state(LinphoneCore *lc, LinphoneGeneralState *gstate){
675}
676
677static void icon_popup_menu(GtkStatusIcon *status_icon, guint button, guint activate_time, gpointer user_data){
678        GtkWidget *menu=(GtkWidget*)g_object_get_data(G_OBJECT(status_icon),"menu");
679        gtk_menu_popup(GTK_MENU(menu),NULL,NULL,gtk_status_icon_position_menu,status_icon,button,activate_time);
680}
681
682void linphone_gtk_open_browser(const char *url){
683#ifdef WIN32
684        ShellExecute(0,"open",url,NULL,NULL,1);
685#else
686        char cl[255];
687        snprintf(cl,sizeof(cl),"/usr/bin/x-www-browser %s",url);
688        g_spawn_command_line_async(cl,NULL);
689#endif
690}
691
692void linphone_gtk_link_to_website(GtkWidget *item){
693        const gchar *home=(const gchar*)g_object_get_data(G_OBJECT(item),"home");
694        linphone_gtk_open_browser(home);
695}
696
697static GtkWidget *create_icon_menu(){
698        GtkWidget *menu=gtk_menu_new();
699        GtkWidget *menu_item;
700        GtkWidget *image;
701        gchar *tmp;
702        const gchar *homesite;
703       
704        homesite=linphone_gtk_get_ui_config("home","http://www.linphone.org");
705        menu_item=gtk_image_menu_item_new_with_label(homesite);
706        tmp=g_strdup(homesite);
707        g_object_set_data(G_OBJECT(menu_item),"home",tmp);
708        g_object_weak_ref(G_OBJECT(menu_item),(GWeakNotify)g_free,tmp);
709       
710        image=gtk_image_new_from_stock(GTK_STOCK_HELP,GTK_ICON_SIZE_MENU);
711        gtk_widget_show(image);
712        gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),image);
713        //g_object_unref(G_OBJECT(image));
714        gtk_widget_show(menu_item);
715        gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item);
716        g_signal_connect(G_OBJECT(menu_item),"activate",(GCallback)linphone_gtk_link_to_website,NULL);
717       
718        menu_item=gtk_image_menu_item_new_from_stock(GTK_STOCK_ABOUT,NULL);
719        gtk_widget_show(menu_item);
720        gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item);
721        g_signal_connect_swapped(G_OBJECT(menu_item),"activate",(GCallback)linphone_gtk_show_about,NULL);
722        menu_item=gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT,NULL);
723        gtk_widget_show(menu_item);
724        gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item);
725        g_signal_connect_swapped(G_OBJECT(menu_item),"activate",(GCallback)gtk_main_quit,NULL);
726        gtk_widget_show(menu);
727        return menu;
728}
729
730static GtkStatusIcon *icon=NULL;
731
732static void linphone_gtk_init_status_icon(){
733        const char *icon_path=linphone_gtk_get_ui_config("icon",LINPHONE_ICON);
734        GdkPixbuf *pbuf=create_pixbuf(icon_path);
735        GtkWidget *menu=create_icon_menu();
736        const char *title;
737        icon=gtk_status_icon_new_from_pixbuf(pbuf);
738        g_object_unref(G_OBJECT(pbuf));
739        g_signal_connect_swapped(G_OBJECT(icon),"activate",(GCallback)linphone_gtk_show_main_window,linphone_gtk_get_main_window());
740        g_signal_connect(G_OBJECT(icon),"popup-menu",(GCallback)icon_popup_menu,NULL);
741        title=linphone_gtk_get_ui_config("title",_("Linphone - a video internet phone"));
742        gtk_status_icon_set_tooltip(icon,title);
743        gtk_status_icon_set_visible(icon,TRUE);
744        g_object_set_data(G_OBJECT(icon),"menu",menu);
745        g_object_weak_ref(G_OBJECT(icon),(GWeakNotify)gtk_widget_destroy,menu);
746}
747
748void linphone_gtk_load_identities(void){
749        const MSList *elem;
750        GtkComboBox *box=GTK_COMBO_BOX(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"identities"));
751        char *def_identity;
752        LinphoneProxyConfig *def=NULL;
753        int def_index=0,i;
754        GtkListStore *store;
755
756        store=GTK_LIST_STORE(gtk_combo_box_get_model(box));
757        gtk_list_store_clear(store);
758
759        linphone_core_get_default_proxy(linphone_gtk_get_core(),&def);
760        def_identity=g_strdup_printf(_("%s (Default)"),linphone_core_get_primary_contact(linphone_gtk_get_core()));
761        gtk_combo_box_append_text(box,def_identity);
762        g_free(def_identity);
763        for(i=1,elem=linphone_core_get_proxy_config_list(linphone_gtk_get_core());
764                        elem!=NULL;
765                        elem=ms_list_next(elem),i++){
766                LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)elem->data;
767                gtk_combo_box_append_text(box,linphone_proxy_config_get_identity(cfg));
768                if (cfg==def) {
769                        def_index=i;
770                }
771        }
772        gtk_combo_box_set_active(box,def_index);
773}
774
775static void linphone_gtk_dtmf_clicked(GtkButton *button){
776        const char *label=gtk_button_get_label(button);
777        linphone_core_send_dtmf(linphone_gtk_get_core(),label[0]);
778}
779
780static void linphone_gtk_connect_digits(void){
781        GtkContainer *cont=GTK_CONTAINER(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"dtmf_table"));
782        GList *children=gtk_container_get_children(cont);
783        GList *elem;
784        for(elem=children;elem!=NULL;elem=elem->next){
785                GtkButton *button=GTK_BUTTON(elem->data);
786                g_signal_connect(G_OBJECT(button),"clicked",(GCallback)linphone_gtk_dtmf_clicked,NULL);
787        }
788}
789
790static void linphone_gtk_check_menu_items(void){
791        bool_t audio_only=!linphone_core_video_enabled(linphone_gtk_get_core());
792        gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(linphone_gtk_get_widget(
793                                        linphone_gtk_get_main_window(),
794                                        audio_only ? "audio_only_item" : "video_item")), TRUE);
795}
796
797static gboolean linphone_gtk_can_manage_accounts(){
798        LinphoneCore *lc=linphone_gtk_get_core();
799        const MSList *elem;
800        for(elem=linphone_core_get_sip_setups(lc);elem!=NULL;elem=elem->next){
801                SipSetup *ss=(SipSetup*)elem->data;
802                if (sip_setup_get_capabilities(ss) & SIP_SETUP_CAP_ACCOUNT_MANAGER){
803                        return TRUE;
804                }
805        }
806        return FALSE;
807}
808
809static void linphone_gtk_configure_main_window(){
810        static gboolean config_loaded=FALSE;
811        static const char *title;
812        static const char *home;
813        static const char *start_call_icon;
814        static const char *stop_call_icon;
815        GtkWidget *w=linphone_gtk_get_main_window();
816        if (!config_loaded){
817                title=linphone_gtk_get_ui_config("title",NULL);
818                home=linphone_gtk_get_ui_config("home","http://www.linphone.org");
819                start_call_icon=linphone_gtk_get_ui_config("start_call_icon",NULL);
820                stop_call_icon=linphone_gtk_get_ui_config("stop_call_icon",NULL);
821                config_loaded=TRUE;
822        }
823        linphone_gtk_configure_window(w,"main_window");
824        if (title) {
825                gtk_window_set_title(GTK_WINDOW(w),title);
826                gtk_menu_item_set_label(GTK_MENU_ITEM(linphone_gtk_get_widget(w,"main_menu")),title);
827        }
828        if (start_call_icon){
829                GdkPixbuf *pbuf=create_pixbuf(start_call_icon);
830                gtk_image_set_from_pixbuf(GTK_IMAGE(linphone_gtk_get_widget(w,"start_call_icon")),pbuf);
831                g_object_unref(G_OBJECT(pbuf));
832        }
833        if (stop_call_icon){
834                GdkPixbuf *pbuf=create_pixbuf(stop_call_icon);
835                gtk_image_set_from_pixbuf(GTK_IMAGE(linphone_gtk_get_widget(w,"terminate_call_icon")),pbuf);
836                g_object_unref(G_OBJECT(pbuf));
837        }
838        if (home){
839                gchar *tmp;
840                GtkWidget *menu_item=linphone_gtk_get_widget(w,"home_item");
841                tmp=g_strdup(home);
842                g_object_set_data(G_OBJECT(menu_item),"home",tmp);
843        }
844        if (!linphone_gtk_can_manage_accounts())
845                gtk_widget_hide(linphone_gtk_get_widget(w,"run_assistant"));
846}
847
848static void linphone_gtk_init_main_window(){
849        linphone_gtk_configure_main_window();
850        load_uri_history();
851        linphone_gtk_load_identities();
852        linphone_gtk_set_my_presence(linphone_core_get_presence_info(linphone_gtk_get_core()));
853        linphone_gtk_show_friends();
854        linphone_gtk_connect_digits();
855        linphone_gtk_check_menu_items();
856        if (linphone_core_in_call(linphone_gtk_get_core())) linphone_gtk_call_started(
857                linphone_gtk_get_main_window());/*hide the call button, show terminate button*/
858}
859
860void linphone_gtk_close(){
861        /* couldn't find a way to prevent closing to destroy the main window*/
862        LinphoneCore *lc=linphone_gtk_get_core();
863        the_ui=NULL;
864        the_ui=linphone_gtk_create_window("main");
865        linphone_gtk_init_main_window();
866        /*shutdown call if any*/
867        if (linphone_core_in_call(lc)){
868                linphone_core_terminate_call(lc,NULL);
869                linphone_gtk_call_terminated(the_ui);
870        }
871        linphone_core_enable_video_preview(lc,FALSE);
872}
873
874void linphone_gtk_log_handler(OrtpLogLevel lev, const char *fmt, va_list args){
875        if (verbose){
876                const char *lname="undef";
877                char *msg;
878                #ifdef __linux
879                va_list cap;/*copy of our argument list: a va_list cannot be re-used (SIGSEGV on linux 64 bits)*/
880                #endif
881                switch(lev){
882                        case ORTP_DEBUG:
883                                lname="debug";
884                                break;
885                        case ORTP_MESSAGE:
886                                lname="message";
887                                break;
888                        case ORTP_WARNING:
889                                lname="warning";
890                                break;
891                        case ORTP_ERROR:
892                                lname="error";
893                                break;
894                        case ORTP_FATAL:
895                                lname="fatal";
896                                break;
897                        default:
898                                g_error("Bad level !");
899                }
900#ifdef __linux
901                va_copy(cap,args);
902                msg=g_strdup_vprintf(fmt,cap);
903                va_end(cap);
904#else
905                msg=g_strdup_vprintf(fmt,args);
906#endif
907                fprintf(stdout,"linphone-%s : %s\n",lname,msg);
908                ortp_free(msg);
909        }
910        linphone_gtk_log_push(lev,fmt,args);
911}
912
913int main(int argc, char *argv[]){
914#ifdef ENABLE_NLS
915        void *p;
916#endif
917        const char *config_file;
918        const char *lang;
919
920        g_thread_init(NULL);
921        gdk_threads_init();
922       
923        config_file=linphone_gtk_get_config_file();
924        if (linphone_core_wake_up_possible_already_running_instance(config_file)==0){
925                g_warning("Another running instance of linphone has been detected. It has been woken-up.");
926                g_warning("This instance is going to exit now.");
927                return 0;
928        }
929#ifdef WIN32
930        /*workaround for windows: sometimes LANG is defined to an integer value, not understood by gtk */
931        if ((lang=getenv("LANG"))!=NULL){
932                if (atoi(lang)!=0){
933                        char tmp[128];
934                        snprintf(tmp,sizeof(tmp),"LANG=",lang);
935                        _putenv(tmp);
936                }
937        }
938#endif
939       
940        if ((lang=linphone_gtk_get_lang(config_file))!=NULL && lang[0]!='\0'){
941#ifdef WIN32
942                char tmp[128];
943                snprintf(tmp,sizeof(tmp),"LANG=%s",lang);
944                _putenv(tmp);
945#else
946                setenv("LANG",lang,1);
947#endif
948        }
949
950#ifdef ENABLE_NLS
951        p=bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
952        if (p==NULL) perror("bindtextdomain failed");
953        bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
954        textdomain (GETTEXT_PACKAGE);
955#else
956        g_message("NLS disabled.\n");
957#endif
958#ifdef WIN32
959        gtk_rc_add_default_file("./gtkrc");
960#endif
961        gdk_threads_enter();
962        if (!gtk_init_with_args(&argc,&argv,_("A free SIP video-phone"),
963                                linphone_options,NULL,NULL)){
964                gdk_threads_leave();
965                return -1;
966        }
967       
968        add_pixmap_directory("pixmaps");
969        add_pixmap_directory(PACKAGE_DATA_DIR "/pixmaps/linphone");
970#ifdef WIN32
971        add_pixmap_directory("linphone");
972#endif
973
974        the_ui=linphone_gtk_create_window("main");
975       
976        linphone_gtk_create_log_window();
977        linphone_core_enable_logs_with_cb(linphone_gtk_log_handler);
978
979        linphone_gtk_init_liblinphone(config_file);
980        /* do not lower timeouts under 30 ms because it exhibits a bug on gtk+/win32, with cpu running 20% all the time...*/
981        gtk_timeout_add(30,(GtkFunction)linphone_gtk_iterate,(gpointer)linphone_gtk_get_core());
982        gtk_timeout_add(30,(GtkFunction)linphone_gtk_check_logs,(gpointer)NULL);
983        linphone_gtk_init_main_window();
984        linphone_gtk_init_status_icon();
985        linphone_gtk_show_main_window();
986        linphone_gtk_check_for_new_version();
987        gtk_main();
988        gdk_threads_leave();
989        linphone_gtk_destroy_log_window();
990        linphone_core_destroy(the_core);
991        /*workaround a bug on win32 that makes status icon still present in the systray even after program exit.*/
992        gtk_status_icon_set_visible(icon,FALSE);
993        return 0;
994}
995
996
Note: See TracBrowser for help on using the repository browser.