[ekiga: 281/281] Merge remote-tracking branch 'origin/ds-gtk-application'



commit 1bdd5d610f4ae6cb14b771eb146d64bafeb378bf
Merge: 05a3ad8 96d93cd
Author: Damien Sandras <dsandras seconix com>
Date:   Thu Dec 25 18:22:23 2014 +0100

    Merge remote-tracking branch 'origin/ds-gtk-application'
    
    Conflicts:
        configure.ac
        lib/Makefile.am
        lib/engine/components/local-roster/local-cluster.cpp
        lib/engine/components/local-roster/local-cluster.h
        lib/engine/components/opal/opal-account.cpp
        lib/engine/components/opal/opal-bank.cpp
        lib/engine/components/opal/sip-chat-simple.cpp
        lib/engine/components/opal/sip-endpoint.cpp
        lib/engine/components/opal/sip-heap.cpp
        lib/engine/components/opal/sip-heap.h
        lib/engine/gui/gtk-frontend/assistant-window.cpp
        lib/engine/gui/gtk-frontend/call-window.cpp
        lib/engine/gui/gtk-frontend/chat-area.cpp
        lib/engine/gui/gtk-frontend/chat-window.cpp
        lib/engine/gui/gtk-frontend/gtk-frontend.cpp
        lib/engine/gui/gtk-frontend/heap-view.cpp
        lib/engine/gui/gtk-frontend/main_window.cpp
        lib/engine/gui/gtk-frontend/roster-view-gtk.cpp
        lib/engine/protocol/call-core.cpp
        lib/engine/protocol/call-core.h
        pixmaps/Makefile.am
        plugins/avahi/Makefile.am
        src/Makefile.am
        src/main.cpp

 .gitignore                                         |    3 +-
 Makefile.am                                        |   17 +-
 TODO                                               |   28 +-
 configure.ac                                       |   17 +-
 lib/Makefile.am                                    |   74 +-
 lib/engine/account/account-core.cpp                |   16 -
 lib/engine/account/account-core.h                  |    6 -
 lib/engine/account/account.h                       |   16 +
 lib/engine/account/bank.h                          |   10 +-
 .../action-provider.cpp}                           |   43 +-
 lib/engine/action/action-provider.h                |   87 +
 src/ekiga.cpp => lib/engine/action/action.cpp      |   76 +-
 lib/engine/action/action.h                         |  187 ++
 lib/engine/action/actor.cpp                        |  153 ++
 lib/engine/action/actor.h                          |  169 ++
 lib/engine/addressbook/book.h                      |    2 +
 lib/engine/addressbook/contact-core.cpp            |   44 -
 lib/engine/addressbook/contact-core.h              |   36 +-
 lib/engine/addressbook/contact.h                   |    4 +-
 lib/engine/addressbook/source.h                    |    2 +
 lib/engine/chat/chat-core.cpp                      |   13 -
 .../components/call-history/history-book.cpp       |   18 +-
 lib/engine/components/call-history/history-book.h  |    7 +-
 .../components/call-history/history-contact.cpp    |   32 +-
 .../components/call-history/history-contact.h      |    4 +-
 .../components/call-history/history-source.cpp     |   11 +-
 .../components/call-history/history-source.h       |    4 +-
 lib/engine/components/foe-list/foe-list.h          |    1 -
 .../components/local-roster/local-cluster.cpp      |  111 -
 lib/engine/components/local-roster/local-cluster.h |  104 -
 lib/engine/components/local-roster/local-heap.cpp  |  499 -----
 lib/engine/components/local-roster/local-heap.h    |  224 --
 .../components/local-roster/local-presentity.cpp   |  485 -----
 .../components/local-roster/local-presentity.h     |  210 --
 .../local-roster/local-roster-bridge.cpp           |  145 --
 .../components/local-roster/local-roster-main.cpp  |   85 -
 .../components/local-roster/local-roster-main.h    |   54 -
 .../mlogo-videoinput/videoinput-manager-mlogo.cpp  |   58 +-
 .../mlogo-videoinput/videoinput-manager-mlogo.h    |    4 +-
 lib/engine/components/opal/h323-endpoint.cpp       |   71 +-
 lib/engine/components/opal/h323-endpoint.h         |   17 +-
 lib/engine/components/opal/opal-account.cpp        |  397 ++--
 lib/engine/components/opal/opal-account.h          |   52 +-
 lib/engine/components/opal/opal-bank.cpp           |  233 +--
 lib/engine/components/opal/opal-bank.h             |   29 +-
 lib/engine/components/opal/opal-call-manager.cpp   |  119 +-
 lib/engine/components/opal/opal-call-manager.h     |   26 +-
 lib/engine/components/opal/opal-call.cpp           |   82 +-
 lib/engine/components/opal/opal-call.h             |   13 +-
 lib/engine/components/opal/opal-main.cpp           |   13 +-
 lib/engine/components/opal/opal-main.h             |    3 +
 lib/engine/components/opal/opal-presentity.cpp     |  118 +-
 lib/engine/components/opal/opal-presentity.h       |   28 +-
 .../engine/components/opal/opal-process.cpp        |   10 +-
 .../engine/components/opal/opal-process.h          |   11 +-
 lib/engine/components/opal/sip-conversation.cpp    |    7 +-
 lib/engine/components/opal/sip-endpoint.cpp        |  101 +-
 lib/engine/components/opal/sip-endpoint.h          |   19 +-
 lib/engine/components/opal/sip-heap.cpp            |   14 +-
 lib/engine/components/opal/sip-heap.h              |    3 -
 lib/engine/engine.cpp                              |   19 +-
 lib/engine/framework/form-builder.cpp              |  100 +-
 lib/engine/framework/form-builder.h                |   84 +-
 lib/engine/framework/form-dumper.cpp               |   41 +-
 lib/engine/framework/form-dumper.h                 |   24 +-
 lib/engine/framework/form-request-simple.cpp       |   13 +-
 lib/engine/framework/form-request-simple.h         |    7 +-
 lib/engine/framework/form-request.h                |    2 +-
 lib/engine/framework/form-visitor.h                |   34 +-
 lib/engine/framework/form.cpp                      |   12 +-
 lib/engine/framework/form.h                        |    8 +-
 lib/engine/framework/live-object.h                 |    5 -
 .../framework/null-deleter.h}                      |   33 +-
 lib/engine/framework/services.cpp                  |    3 +-
 lib/engine/gui/gtk-core/codecsbox.cpp              |   16 +-
 lib/engine/gui/gtk-core/form-dialog-gtk.cpp        |  687 ++++---
 lib/engine/gui/gtk-core/form-dialog-gtk.h          |   43 +-
 lib/engine/gui/gtk-core/gactor-menu.cpp            |  263 +++
 lib/engine/gui/gtk-core/gactor-menu.h              |  146 ++
 lib/engine/gui/gtk-core/gtk-core.cpp               |    3 -
 lib/engine/gui/gtk-core/menu-builder-gtk.cpp       |   35 +-
 lib/engine/gui/gtk-core/optional-buttons-gtk.cpp   |  130 --
 lib/engine/gui/gtk-core/optional-buttons-gtk.h     |  122 --
 lib/engine/gui/gtk-frontend/accounts-window.cpp    |  710 ------
 lib/engine/gui/gtk-frontend/accounts-window.h      |   94 -
 lib/engine/gui/gtk-frontend/addressbook-window.cpp |  593 +++---
 lib/engine/gui/gtk-frontend/addressbook-window.h   |    4 +-
 lib/engine/gui/gtk-frontend/assistant-window.cpp   |  266 +--
 lib/engine/gui/gtk-frontend/assistant-window.h     |   13 +-
 lib/engine/gui/gtk-frontend/book-view-gtk.cpp      |  454 +++--
 lib/engine/gui/gtk-frontend/book-view-gtk.h        |   16 +-
 .../gui/gtk-frontend/call-history-view-gtk.cpp     |  240 +--
 .../gui/gtk-frontend/call-history-view-gtk.h       |   11 +-
 lib/engine/gui/gtk-frontend/call-window.cpp        | 2249 +++++++-------------
 lib/engine/gui/gtk-frontend/call-window.h          |   10 +-
 lib/engine/gui/gtk-frontend/chat-area.cpp          |   19 +-
 lib/engine/gui/gtk-frontend/chat-window.cpp        |   50 +-
 lib/engine/gui/gtk-frontend/chat-window.h          |    4 +-
 lib/engine/gui/gtk-frontend/conversation-page.cpp  |   10 -
 lib/engine/gui/gtk-frontend/ekiga-app.cpp          | 1036 +++++++++
 lib/engine/gui/gtk-frontend/ekiga-app.h            |  117 +
 lib/engine/gui/gtk-frontend/gtk-frontend.cpp       |  280 ---
 lib/engine/gui/gtk-frontend/gtk-frontend.h         |   99 -
 lib/engine/gui/gtk-frontend/heap-view.cpp          |  740 -------
 lib/engine/gui/gtk-frontend/heap-view.h            |   85 -
 lib/engine/gui/gtk-frontend/main_window.cpp        | 1149 ++--------
 lib/engine/gui/gtk-frontend/main_window.h          |    6 +-
 lib/engine/gui/gtk-frontend/preferences-window.cpp |  285 ++--
 lib/engine/gui/gtk-frontend/preferences-window.h   |   12 +-
 lib/engine/gui/gtk-frontend/presentity-view.cpp    |   33 -
 lib/engine/gui/gtk-frontend/roster-view-gtk.cpp    |  537 +++--
 lib/engine/gui/gtk-frontend/roster-view-gtk.h      |   16 +-
 lib/engine/gui/gtk-frontend/statusicon.cpp         |  119 +-
 lib/engine/gui/gtk-frontend/statusicon.h           |    4 +-
 lib/engine/plugin/plugin-core.cpp                  |    2 -
 lib/engine/presence/heap.h                         |   11 +-
 lib/engine/presence/presence-core.cpp              |   38 -
 lib/engine/presence/presence-core.h                |   52 +-
 lib/engine/presence/presentity.h                   |    6 +-
 lib/engine/presence/proxy-presentity.cpp           |   83 -
 lib/engine/presence/proxy-presentity.h             |  102 -
 lib/engine/presence/uri-presentity.cpp             |   15 +-
 lib/engine/presence/uri-presentity.h               |   12 +-
 lib/engine/protocol/call-core.cpp                  |  108 +-
 lib/engine/protocol/call-core.h                    |   47 +-
 lib/engine/protocol/call-manager.h                 |   43 +-
 lib/engine/protocol/call-protocol-manager.h        |   38 +-
 lib/engine/protocol/call.h                         |   15 +-
 lib/engine/videoinput/videoinput-core.cpp          |   10 -
 lib/gui/dialpad.c                                  |   53 +-
 lib/gui/gm-cell-renderer-expander.c                |  367 ++++
 lib/gui/gm-cell-renderer-expander.h                |   78 +
 lib/gui/gm-entry.c                                 |  472 ++++
 lib/gui/gm-entry.h                                 |  169 ++
 lib/gui/gm-info-bar.c                              |  267 +++
 lib/gui/gm-info-bar.h                              |  104 +
 lib/gui/gm-sidebar.c                               |  526 +++++
 lib/gui/gm-sidebar.h                               |   64 +
 lib/gui/gmcallbacks.c                              |  219 --
 lib/gui/gmcallbacks.h                              |   74 -
 lib/gui/gmcellrendererexpander.c                   |  345 ---
 lib/gui/gmcellrendererexpander.h                   |   60 -
 lib/gui/gmentrydialog.c                            |  130 --
 lib/gui/gmentrydialog.h                            |  109 -
 lib/gui/gmmenuaddon.c                              |  459 ----
 lib/gui/gmmenuaddon.h                              |  183 --
 lib/gui/gmpowermeter.c                             |  209 --
 lib/gui/gmpowermeter.h                             |  141 --
 lib/gui/gmstatusbar.c                              |  205 --
 lib/gui/gmstatusbar.h                              |  112 -
 lib/gui/gmstockicons.c                             |   93 -
 lib/gui/gmwindow.c                                 |   50 +-
 lib/gui/gmwindow.h                                 |   25 +-
 org.gnome.ekiga.gschema.xml.in.in                  |   13 +
 pixmaps/128x128/multimedia-headset.png             |  Bin 12120 -> 0 bytes
 pixmaps/128x128/multimedia-headset.svg             | 1412 ------------
 pixmaps/16x16/audio-volume.png                     |  Bin 685 -> 0 bytes
 pixmaps/16x16/brightness.png                       |  Bin 356 -> 0 bytes
 pixmaps/16x16/color.png                            |  Bin 577 -> 0 bytes
 pixmaps/16x16/contrast.png                         |  Bin 625 -> 0 bytes
 pixmaps/16x16/im-message-new.png                   |  Bin 693 -> 0 bytes
 pixmaps/16x16/multimedia-headset.png               |  Bin 816 -> 0 bytes
 pixmaps/16x16/multimedia-headset.svg               |  345 ---
 pixmaps/16x16/video-settings.png                   |  Bin 920 -> 0 bytes
 pixmaps/16x16/whiteness.png                        |  Bin 358 -> 0 bytes
 pixmaps/22x22/multimedia-headset.png               |  Bin 1219 -> 0 bytes
 pixmaps/22x22/multimedia-headset.svg               |  407 ----
 pixmaps/256x256/multimedia-headset.png             |  Bin 31534 -> 0 bytes
 pixmaps/32x32/multimedia-headset.png               |  Bin 1884 -> 0 bytes
 pixmaps/32x32/multimedia-headset.svg               |  632 ------
 pixmaps/48x48/multimedia-headset.png               |  Bin 3354 -> 0 bytes
 pixmaps/HOWTO                                      |   11 -
 pixmaps/Makefile.am                                |  136 +-
 pixmaps/conv-icon.pl                               |   18 +-
 pixmaps/{256x256 => }/ekiga-full-icon.png          |  Bin 28340 -> 28340 bytes
 pixmaps/gm_powermeter_default_00.xpm               |  101 -
 pixmaps/gm_powermeter_default_01.xpm               |   98 -
 pixmaps/gm_powermeter_default_02.xpm               |   84 -
 pixmaps/gm_powermeter_default_03.xpm               |   62 -
 pixmaps/gm_powermeter_default_04.xpm               |   29 -
 .../gnome_actions_128x128_mute-video-symbolic.png  |  Bin 0 -> 2676 bytes
 ...p.png => gnome_actions_16x16_phone-hang-up.png} |  Bin 605 -> 605 bytes
 ...p.png => gnome_actions_16x16_phone-pick-up.png} |  Bin 695 -> 695 bytes
 ...p.png => gnome_actions_24x24_phone-hang-up.png} |  Bin 1149 -> 1149 bytes
 ...p.png => gnome_actions_24x24_phone-pick-up.png} |  Bin 1215 -> 1215 bytes
 .../gnome_actions_scalable_call-hold-symbolic.svg  |   33 +
 ...actions_scalable_call-transfer-symbolic-rtl.svg |   33 +
 ...ome_actions_scalable_call-transfer-symbolic.svg |   33 +
 .../gnome_actions_scalable_mute-video-symbolic.svg |   32 +
 ...ssage.png => gnome_status_16x16_im-message.png} |  Bin 510 -> 510 bytes
 ...all.png => gnome_status_16x16_user-inacall.png} |  Bin 676 -> 676 bytes
 .../ekiga.png => hicolor_apps_128x128_ekiga.png}   |  Bin 11034 -> 11034 bytes
 .../ekiga.png => hicolor_apps_16x16_ekiga.png}     |  Bin 882 -> 882 bytes
 .../ekiga.png => hicolor_apps_22x22_ekiga.png}     |  Bin 1407 -> 1407 bytes
 .../ekiga.png => hicolor_apps_24x24_ekiga.png}     |  Bin 1432 -> 1432 bytes
 .../ekiga.png => hicolor_apps_32x32_ekiga.png}     |  Bin 2178 -> 2178 bytes
 .../ekiga.png => hicolor_apps_48x48_ekiga.png}     |  Bin 3702 -> 3702 bytes
 .../ekiga.png => hicolor_apps_64x64_ekiga.png}     |  Bin 4989 -> 4989 bytes
 .../ekiga.png => hicolor_apps_72x72_ekiga.png}     |  Bin 4872 -> 4872 bytes
 pixmaps/icon.h                                     | 2000 +++++++++++++-----
 pixmaps/scalable/multimedia-headset.svg            |  667 ------
 plugins/avahi/Makefile.am                          |    2 +
 plugins/avahi/avahi-heap.cpp                       |    4 +-
 plugins/evolution/Makefile.am                      |    1 +
 plugins/evolution/evolution-book.cpp               |   42 +-
 plugins/evolution/evolution-book.h                 |    8 +-
 plugins/evolution/evolution-contact.cpp            |  109 +-
 plugins/evolution/evolution-contact.h              |   12 +-
 plugins/kab/kab-book.h                             |    2 +-
 plugins/ldap/Makefile.am                           |    1 +
 plugins/ldap/ldap-book.cpp                         |  105 +-
 plugins/ldap/ldap-book.h                           |   12 +-
 plugins/ldap/ldap-contact.cpp                      |   25 -
 plugins/ldap/ldap-contact.h                        |    2 -
 plugins/ldap/ldap-source.cpp                       |   34 +-
 plugins/ldap/ldap-source.h                         |    7 +-
 plugins/libnotify/Makefile.am                      |    2 +
 plugins/loudmouth/loudmouth-account.cpp            |    4 +-
 plugins/loudmouth/loudmouth-bank.cpp               |    4 +-
 plugins/loudmouth/loudmouth-heap-roster.cpp        |   28 +-
 plugins/loudmouth/loudmouth-heap-roster.h          |    2 +-
 plugins/resource-list/rl-cluster.cpp               |   15 +-
 plugins/resource-list/rl-cluster.h                 |    5 +-
 plugins/resource-list/rl-heap.cpp                  |   26 +-
 plugins/resource-list/rl-heap.h                    |   10 +-
 plugins/resource-list/rl-presentity.cpp            |   11 +-
 plugins/resource-list/rl-presentity.h              |    5 +-
 src/Makefile.am                                    |   11 +-
 src/dbus-helper/dbus.cpp                           |   28 +-
 src/dbus-helper/dbus.h                             |    4 +-
 src/main.cpp                                       |  198 +--
 231 files changed, 10576 insertions(+), 16901 deletions(-)
---
diff --cc TODO
index 0fb1ad0,ff0c643..3890c66
--- a/TODO
+++ b/TODO
@@@ -1,5 -1,28 +1,29 @@@
  See our wiki: http://wiki.ekiga.org/index.php/ToDo
- - Check what happens when we hide the window. Can we get it back when we want ?
- - Update DOC with 4.0 screenshots
+ - clean up signal relay. No need to have a class method for each signal "relay".
+ - Check what happens when we hide the window. Can we get it back when we want ? DONE
+ - Update DOC with 5.0 screenshots
  - Make sure that automatic reREGISTER and presence reSUBSCRIBE/PUBLISH still works when a registrar is down 
then comes online.
  - Make sure refresh also works as expected.
+ - Simplify Call Core code by using signal relay (boost::ref)
+ - Turn LiveObject into an Actor ?
+ - add_heap does not seem to be used anymore
+ - questions from Account Edition relayed to PresenceCore ? Well why not.
+ - GSettings migration ? To check.
+ - Roster migration : to implement + implement adding Echo test and such to the roster when it is not empty.
+ - trackable object (in .h ?)
+ - Is Heap-Impl still used in the OPAL component ?
+ - This existing_group function passed to the Opal::Account ctor is so weiiiiiird....
+ - Proof check all dialogs. e.g. can we delete the SIP URI of a roster contact and save it ?
+ - Forms error checking should be simplified. Perhaps with "allow_empty" properties ? and URI handling ? DONE
+ - Check Forms for mnemonics.
+ - Check Accels
+ - Prefs should perhaps use GtkInfoBar to prevent entering wrong forward uris.
+ - Use GtkInfoBar instead of GmStatusBar. DONE
+ - Clean icons & pixmaps.
+ - Call Window : add / remove entries -> concert to add + disable actions
+ - Contact phone numbers: open a popup with all possibilities instead of right-click popup => 1 action. 
Urgent.
+ - Cleanup Ekiga App. Not sure everything is initialized at the right place.
+ - Cleanup files (e.g. codecsbox which is frontend, not core)
+ - Roster should be refreshed when accounts are added/removed
+ - Global actions should be updated if an Ekiga.net/DiamondCard is added/removed.
++- Call Window: on_setup_call, check if it is the right place for blacklist handling + status change 
("calling", isn't it called on incoming calls too ?)
diff --cc lib/Makefile.am
index 5c7a7a9,72f657b..63ba0fc
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@@ -34,11 -39,8 +35,10 @@@ AM_CPPFLAGS = 
        -I$(top_srcdir)/lib/engine/videooutput \
        -I$(top_srcdir)/lib/engine/components/call-history \
        -I$(top_srcdir)/lib/engine/components/echo \
 +      -I$(top_srcdir)/lib/engine/components/foe-list \
        -I$(top_srcdir)/lib/engine/components/gmconf-personal-details \
        -I$(top_srcdir)/lib/engine/components/hal-dbus \
 +      -I$(top_srcdir)/lib/engine/components/hal-gudev \
-       -I$(top_srcdir)/lib/engine/components/local-roster \
        -I$(top_srcdir)/lib/engine/components/mlogo-videoinput \
        -I$(top_srcdir)/lib/engine/components/null-audioinput \
        -I$(top_srcdir)/lib/engine/components/null-audiooutput \
@@@ -363,12 -397,12 +370,10 @@@ libekiga_la_SOURCES += 
        engine/gui/gtk-frontend/default_devices.h \
        engine/gui/gtk-frontend/presentity-view.h \
        engine/gui/gtk-frontend/presentity-view.cpp \
-       engine/gui/gtk-frontend/heap-view.h \
-       engine/gui/gtk-frontend/heap-view.cpp \
        engine/gui/gtk-frontend/chat-area.h \
        engine/gui/gtk-frontend/chat-area.cpp \
 -      engine/gui/gtk-frontend/simple-chat-page.h \
 -      engine/gui/gtk-frontend/simple-chat-page.cpp \
 -      engine/gui/gtk-frontend/multiple-chat-page.h \
 -      engine/gui/gtk-frontend/multiple-chat-page.cpp \
 +      engine/gui/gtk-frontend/conversation-page.h \
 +      engine/gui/gtk-frontend/conversation-page.cpp \
        engine/gui/gtk-frontend/preferences-window.cpp \
        engine/gui/gtk-frontend/preferences-window.h \
        engine/gui/gtk-frontend/statusicon.cpp \
diff --cc lib/engine/components/call-history/history-book.cpp
index 80b4044,be69b14..4588339
--- a/lib/engine/components/call-history/history-book.cpp
+++ b/lib/engine/components/call-history/history-book.cpp
@@@ -78,10 -78,16 +78,16 @@@ History::Book::Book (Ekiga::ServiceCore
  
    boost::shared_ptr<Ekiga::CallCore> call_core = core.get<Ekiga::CallCore> ("call-core");
  
 -  call_core->missed_call.connect (boost::bind (&History::Book::on_missed_call, this, _1, _2));
 -  call_core->cleared_call.connect (boost::bind (&History::Book::on_cleared_call, this, _1, _2, _3));
 +  connections.add (call_core->missed_call.connect (boost::bind (&History::Book::on_missed_call, this, _1, 
_2)));
 +  connections.add (call_core->cleared_call.connect (boost::bind (&History::Book::on_cleared_call, this, _1, 
_2, _3)));
  
    enforce_size_limit ();
+ 
+   /* Actor actions should be added */
+   add_action (Ekiga::ActionPtr (new Ekiga::Action ("history_book_clear",
+                                                    _("Clear History"),
+                                                    boost::bind (&History::Book::clear,
+                                                                 this))));
  }
  
  History::Book::~Book ()
diff --cc lib/engine/components/foe-list/foe-list.h
index 26e816b,be0bfa1..7bdaa3f
--- a/lib/engine/components/foe-list/foe-list.h
+++ b/lib/engine/components/foe-list/foe-list.h
@@@ -33,53 -33,40 +33,52 @@@
   *
   */
  
 -#ifndef __ECHO_DIALECT_H__
 -#define __ECHO_DIALECT_H__
 +#ifndef __FOE_LIST_H__
 +#define __FOE_LIST_H__
  
 -#include "services.h"
 -#include "dialect-impl.h"
 -#include "echo-simple.h"
 +#include "contact-core.h"
 +#include "friend-or-foe.h"
  
 -namespace Echo
 +namespace Ekiga
  {
 -  class Dialect:
 -    public Ekiga::Service,
 -    public Ekiga::DialectImpl<SimpleChat>
 +
 +  class FoeList:
 +    public Service,
-     public ContactDecorator,
 +    public FriendOrFoe::Helper
    {
    public:
 -    
 -    Dialect ();
 +    FoeList(boost::shared_ptr<FriendOrFoe> friend_or_foo);
  
 -    ~Dialect ();
 +    ~FoeList();
  
 -    bool populate_menu (Ekiga::MenuBuilder &builder);
 +    /* Ekiga::Service api */
  
      const std::string get_name () const
 -    { return "echo-dialect"; }
 +    { return "foe-list"; }
  
      const std::string get_description () const
 -    { return "\tProvides an echo chat for testing purposes"; }
 +    { return "List of persons the user does not want to hear about"; }
  
 -  private:
 +    /* Ekiga::ContactDecorator api */
  
 -    void new_chat ();
 -  };
 +    bool populate_menu (ContactPtr contact,
 +                      const std::string uri,
 +                      MenuBuilder& builder);
 +
 +    /* Ekiga::FriendOrFoe::Helper api */
 +
 +    FriendOrFoe::Identification decide (const std::string domain,
 +                                      const std::string token) const;
  
 -  typedef boost::shared_ptr<Dialect> DialectPtr;
 +    /* specific api */
  
 +    void add_foe (const std::string token);
 +
 +  private:
 +
 +    // beware of dependency loops!
 +    boost::weak_ptr<FriendOrFoe> friend_or_foe;
 +  };
  };
  
  #endif
diff --cc lib/engine/components/opal/opal-account.cpp
index 4d2fdc6,aaa1a98..dcaf94a
--- a/lib/engine/components/opal/opal-account.cpp
+++ b/lib/engine/components/opal/opal-account.cpp
@@@ -866,10 -866,7 +857,10 @@@ Opal::Account::publish (const Ekiga::Pe
    presence_status = details.get_status ();
  
    if (presentity) {
-     OpalPresenceInfo opi = OpalPresenceInfo (OpalPresenceInfo::Available);
 -    presentity->SetLocalPresence (personal_state, presence_status);
++    OpalPresenceInfo opi = OpalPresenceInfo (personal_state);
 +    opi.m_activities = PString (presence);
 +    opi.m_note = presence_status;
 +    presentity->SetLocalPresence (opi);
      PTRACE (4, "Ekiga\tSent its own presence (publish) for " << get_aor() << ": " << presence << ", note " 
<< presence_status);
    }
  }
@@@ -921,10 -918,10 +912,10 @@@ Opal::Account::handle_registration_even
        failed_registration_already_notified = false;
        if (presentity) {
  
-         for (const_iterator iter = begin ();
-              iter != end ();
 -      for (Ekiga::RefLister< Presentity >::const_iterator iter = Ekiga::RefLister< Presentity >::begin ();
 -           iter != Ekiga::RefLister< Presentity >::end ();
 -           ++iter)
 -        fetch ((*iter)->get_uri());
++        for (Ekiga::RefLister<Presentity>::const_iterator iter = Ekiga::RefLister<Presentity>::begin ();
++             iter != Ekiga::RefLister<Presentity>::end ();
 +             ++iter)
 +          fetch ((*iter)->get_uri());
  
          presentity->SetLocalPresence (personal_state, presence_status);
          if (type != Account::H323) {
@@@ -1012,16 -1003,13 +1003,16 @@@
            std::stringstream msg;
            msg << _("Could not register to ") << get_name ();
            boost::shared_ptr<Ekiga::Notification> notif (new Ekiga::Notification 
(Ekiga::Notification::Warning, msg.str (), info, _("Edit"), boost::bind (&Opal::Account::edit, 
(Opal::Account*) this)));
-       boost::shared_ptr<Ekiga::NotificationCore> ncore = notification_core.lock ();
-       if (ncore)
-           ncore->push_notification (notif);
+           boost::shared_ptr<Ekiga::NotificationCore> ncore = notification_core.lock ();
+           if (ncore)
+             ncore->push_notification (notif);
+           updated ();
          }
-         updated ();
          failed_registration_already_notified = true;
          break;
 +      case SIPRegister::EndCompatibilityModes:
 +        // bookkeeping code, to remove a compile warning
 +        break;
        default:
  
          state = state_;
diff --cc lib/engine/components/opal/opal-bank.h
index 630b2b5,0930f80..384e7c3
--- a/lib/engine/components/opal/opal-bank.h
+++ b/lib/engine/components/opal/opal-bank.h
@@@ -116,11 -103,8 +102,11 @@@ public
      /* this object is an Ekiga::Cluster */
      void visit_heaps (boost::function1<bool, Ekiga::HeapPtr> visitor) const;
  
-     const std::set<std::string> existing_groups () const;
+     const std::list<std::string> existing_groups () const;
  
 +    /* this is useful when we want to do something with some uri and
 +       would like to avoid creating a brand-new presentity on it */
 +    Ekiga::PresentityPtr find_presentity_for_uri (const std::string uri) const;
  
      // FIXME: only here for the transition off gconf
      static void migrate_from_gconf (const std::list<std::string> old);
diff --cc lib/engine/components/opal/opal-main.cpp
index a2d00ba,ccd7e3c..1253867
--- a/lib/engine/components/opal/opal-main.cpp
+++ b/lib/engine/components/opal/opal-main.cpp
@@@ -38,8 -38,8 +38,9 @@@
  #include "config.h"
  
  #include "opal-main.h"
+ #include "opal-process.h"
  
 +#include "account-core.h"
  #include "chat-core.h"
  #include "presence-core.h"
  #include "audioinput-core.h"
diff --cc lib/engine/components/opal/sip-conversation.cpp
index ec1bd01,0000000..d193aa3
mode 100644,000000..100644
--- a/lib/engine/components/opal/sip-conversation.cpp
+++ b/lib/engine/components/opal/sip-conversation.cpp
@@@ -1,89 -1,0 +1,92 @@@
 +
 +/*
 + * Ekiga -- A VoIP and Video-Conferencing application
 + * Copyright (C) 2000-2014 Damien Sandras <dsandras seconix com>
 +
 + * This program is free software; you can  redistribute it and/or modify
 + * it under the terms of the GNU General Public License as published by
 + * the Free Software Foundation; either version 2 of the License, or (at
 + * your option) any later version. This program is distributed in the hope
 + * that it will be useful, but WITHOUT ANY WARRANTY; without even the
 + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 + * See the GNU General Public License for more details.
 + *
 + * You should have received a copy of the GNU General Public License along
 + * with this program; if not, write to the Free Software Foundation, Inc.,
 + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
 + *
 + * Ekiga is licensed under the GPL license and as a special exception, you
 + * have permission to link or otherwise combine this program with the
 + * programs OPAL, OpenH323 and PWLIB, and distribute the combination, without
 + * applying the requirements of the GNU GPL to the OPAL, OpenH323 and PWLIB
 + * programs, as long as you do follow the requirements of the GNU GPL for all
 + * the rest of the software thus combined.
 + */
 +
 +
 +/*
 + *                         sip-conversation.cpp -  description
 + *                         ------------------------------------------
 + *   begin                : written in 2014 by Julien Puydt
 + *   copyright            : (c) 2014 by Julien Puydt
 + *   description          : implementation of a SIP conversation
 + *
 + */
 +
 +#include "sip-conversation.h"
 +#include "uri-presentity.h"
 +
 +SIP::Conversation::Conversation (boost::shared_ptr<Ekiga::PresenceCore> _core,
 +                               const std::string _uri,
 +                               const std::string _name,
 +                               boost::function1<bool, const Ekiga::Message::payload_type&> _sender):
 +  presence_core(_core), uri(_uri), title(_name), sender(_sender), unreads(0)
 +{
 +  // FIXME: this api isn't good: we obviously don't handle correctly Conversation with several people!
 +  boost::shared_ptr<Ekiga::URIPresentity> presentity =
-     boost::shared_ptr<Ekiga::URIPresentity> (new Ekiga::URIPresentity (_core, title, uri,
-                                                                      std::set<std::string> ()));
++    boost::shared_ptr<Ekiga::URIPresentity> (new Ekiga::URIPresentity (_core,
++                                                                       title,
++                                                                       uri,
++                                                                       std::list<std::string>
++                                                                       ()));
 +  heap  = boost::shared_ptr<Heap> (new Heap);
 +  heap->add_presentity (boost::dynamic_pointer_cast<Ekiga::Presentity> (presentity));
 +}
 +
 +void
 +SIP::Conversation::visit_messages (boost::function1<bool, const Ekiga::Message&> visitor) const
 +{
 +  for (std::list<Ekiga::Message>::const_iterator iter = messages.begin();
 +       iter != messages.end ();
 +       ++iter) {
 +
 +    if (!visitor(*iter))
 +      break;
 +  }
 +}
 +
 +bool
 +SIP::Conversation::send_message (const Ekiga::Message::payload_type& payload)
 +{
 +  return sender (payload);
 +}
 +
 +void
 +SIP::Conversation::reset_unread_messages_count ()
 +{
 +  unreads = 0;
 +  updated ();
 +}
 +
 +void
 +SIP::Conversation::receive_message (const Ekiga::Message& message)
 +{
 +  // if the endpoint doesn't put a real name, we'll try to find one
 +  Ekiga::Message msg = { message.time,
 +                       heap->get_name (message.name),
 +                       message.payload };
 +  messages.push_back (msg);
 +  message_received (msg);
 +  unreads++;
 +  updated();
 +}
diff --cc lib/engine/components/opal/sip-endpoint.cpp
index 36bfa6e,9d0aaef..c53d1ba
--- a/lib/engine/components/opal/sip-endpoint.cpp
+++ b/lib/engine/components/opal/sip-endpoint.cpp
@@@ -178,34 -174,16 +178,18 @@@ Opal::Sip::EndPoint::setup (std::strin
  
  
  bool
- Opal::Sip::EndPoint::populate_menu (const std::string& fullname,
-                                   const std::string& uri,
-                                   Ekiga::MenuBuilder& builder)
- {
-   if (0 == GetConnectionCount ())
-     builder.add_action ("phone-pick-up", _("Call"),
-                       boost::bind (&Opal::Sip::EndPoint::on_dial, this, uri));
-   else
-     builder.add_action ("mail-forward", _("Transfer"),
-                       boost::bind (&Opal::Sip::EndPoint::on_transfer, this, uri));
-   builder.add_action ("im-message-new", _("Message"),
-                     boost::bind (&Opal::Sip::EndPoint::on_message, this, uri, fullname));
- 
-   return true;
- }
- 
- 
- bool
  Opal::Sip::EndPoint::send_message (const std::string & _uri,
 -                                 const std::string & _message)
 +                                 const Ekiga::Message::payload_type payload)
  {
 -  if (is_supported_uri (_uri) && !_message.empty ()) {
 +  // FIXME: here we should check which kind of payload we have
 +  Ekiga::Message::payload_type::const_iterator iter = payload.find("text/plain");
 +  if (!_uri.empty () && (_uri.find ("sip:") == 0 || _uri.find (':') == string::npos) && iter != payload.end 
()) {
+ 
      OpalIM im;
      im.m_to = PURL (_uri);
 -    im.m_mimeType = "text/plain;charset=UTF-8";
 -    im.m_body = _message;
 +    im.m_bodies.SetAt (PMIMEInfo::TextPlain(), iter->second);
      Message (im);
++
      return true;
    }
  
@@@ -927,32 -923,20 +955,11 @@@ Opal::Sip::EndPoint::OnDialogInfoReceiv
  }
  
  
- void Opal::Sip::EndPoint::on_dial (std::string uri)
- {
-   manager.dial (uri);
- }
- 
- 
- void Opal::Sip::EndPoint::on_message (std::string uri,
-                                       std::string name)
- {
-   dialect->start_chat_with (uri, name);
- }
- 
- 
- void Opal::Sip::EndPoint::on_transfer (std::string uri)
- {
-   /* FIXME : we don't handle several calls here */
-   for (PSafePtr<OpalConnection> connection(connectionsActive, PSafeReference); connection != NULL; 
++connection)
-     if (!PIsDescendant(&(*connection), OpalPCSSConnection))
-       connection->TransferConnection (uri);
- }
- 
  void
  Opal::Sip::EndPoint::push_message_in_main (const std::string uri,
 -                                         const std::string name,
 -                                         const std::string msg)
 -{
 -  dialect->push_message (uri, name, msg);
 -}
 -
 -void
 -Opal::Sip::EndPoint::push_notice_in_main (const std::string uri,
 -                                        const std::string name,
 -                                        const std::string msg)
 +                                         const Ekiga::Message msg)
  {
 -  dialect->push_notice (uri, name, msg);
 +  dialect->push_message (uri, msg);
  }
  
  void
diff --cc lib/engine/components/opal/sip-endpoint.h
index a25745b,36a8b46..4104755
--- a/lib/engine/components/opal/sip-endpoint.h
+++ b/lib/engine/components/opal/sip-endpoint.h
@@@ -168,13 -169,13 +168,8 @@@ namespace Opal 
  
        /* Callbacks */
      private:
-       void on_dial (std::string uri);
-       void on_message (std::string uri,
-                      std::string name);
-       void on_transfer (std::string uri);
- 
        void push_message_in_main (const std::string uri,
 -                               const std::string name,
 -                               const std::string msg);
 -
 -      void push_notice_in_main (const std::string uri,
 -                              const std::string name,
 -                              const std::string msg);
 +                               const Ekiga::Message msg);
  
        PMutex aorMutex;
        std::map<std::string, std::string> accounts;
diff --cc lib/engine/components/opal/sip-heap.cpp
index 7a8e0e9,a8854a4..3e23615
--- a/lib/engine/components/opal/sip-heap.cpp
+++ b/lib/engine/components/opal/sip-heap.cpp
@@@ -33,45 -34,34 +33,33 @@@
   *
   */
  
 -#ifndef __CHAT_MULTIPLE_H__
 -#define __CHAT_MULTIPLE_H__
 +#include "sip-heap.h"
 +#include "uri-presentity.h"
  
- bool
- SIP::Heap::populate_menu (Ekiga::MenuBuilder& /*builder*/)
- {
-   return false;
- }
 -#include <boost/smart_ptr.hpp>
  
 -#include "chat.h"
 -#include "heap.h"
 -
 -namespace Ekiga
 +const std::string
 +SIP::Heap::get_name () const
  {
 +  return ""; // FIXME?
 +}
  
- bool
- SIP::Heap::populate_menu_for_group (const std::string /*name*/,
-                                   Ekiga::MenuBuilder& /*builder*/)
- {
-   return false;
- }
- 
 -  class MultipleChat: public Chat
 -  {
 -  public:
 -
 -    /** The destructor.
 -     */
 -    virtual ~MultipleChat ()
 -    {}
 -
 -    /** Returns the Heap associated with the MultipleChat.
 -     * @return The MultipleChat's Heap
 -     */
 -    virtual HeapPtr get_heap () const = 0;
 -  };
 +const std::string
 +SIP::Heap::get_name (const std::string uri) const
 +{
 +  bool found = false;
 +  std::string result = uri; // sensible default
  
 -  typedef boost::shared_ptr<MultipleChat> MultipleChatPtr;
 +  for (const_iterator iter = begin ();
 +       iter != end () and not found;
 +       ++iter) {
  
 -};
 +    boost::shared_ptr<Ekiga::URIPresentity> pres
 +      = boost::dynamic_pointer_cast<Ekiga::URIPresentity> (*iter);
 +    if (pres and pres->get_uri () == uri) {
-       
+ 
 -#endif
 +      found = true;
 +      result = pres->get_name ();
 +    }
 +  }
 +  return result;
 +}
diff --cc lib/engine/components/opal/sip-heap.h
index 70e7811,f60a1ea..bbf6feb
--- a/lib/engine/components/opal/sip-heap.h
+++ b/lib/engine/components/opal/sip-heap.h
@@@ -33,29 -33,39 +33,26 @@@
   *
   */
  
 -#ifndef __ECHO_PRESENTITY__
 -#define __ECHO_PRESENTITY__
 +#ifndef __SIP_HEAP_H__
 +#define __SIP_HEAP_H__
  
 -#include <boost/smart_ptr.hpp>
 -#include "presentity.h"
 +#include "heap-impl.h"
  
 -namespace Echo
 +namespace SIP
  {
 -  class Presentity: public Ekiga::Presentity
 +  class Heap: public Ekiga::HeapImpl<Ekiga::Presentity>
    {
    public:
 +    // let's put everything in public so SIP::Conversation can control us fully!
 +    using Ekiga::HeapImpl<Ekiga::Presentity>::add_presentity;
 +    using Ekiga::HeapImpl<Ekiga::Presentity>::remove_presentity;
 +    using Ekiga::HeapImpl<Ekiga::Presentity>::add_connection;
  
-     bool populate_menu (Ekiga::MenuBuilder& builder);
 -    Presentity ();
 -
 -    ~Presentity ();
 -
 +    // this is the heap's name
      const std::string get_name () const;
 -
 -    const std::string get_presence () const;
 -
 -    const std::string get_status () const;
 -
 -    const std::list<std::string> get_groups () const;
 -
 -    const std::string get_uri () const;
 -
 -    bool has_uri (const std::string uri) const;
 -
 -    bool populate_menu (Ekiga::MenuBuilder &);
 +    // try to find a nice name to display from the uri of a presentity
 +    const std::string get_name (const std::string uri) const;
-     bool populate_menu_for_group (const std::string name,
-                                 Ekiga::MenuBuilder& builder);
    };
 -
 -  typedef boost::shared_ptr<Presentity> PresentityPtr;
 -
  };
  
  #endif
diff --cc lib/engine/engine.cpp
index e302429,9aa88b2..9150aa3
--- a/lib/engine/engine.cpp
+++ b/lib/engine/engine.cpp
@@@ -204,11 -183,6 +195,9 @@@ engine_init (Ekiga::ServiceCorePtr serv
    hal_core->audioinput_device_added.connect (boost::bind (&Ekiga::AudioInputCore::add_device, boost::ref 
(*audioinput_core), _1, _2, _3));
    hal_core->audioinput_device_removed.connect (boost::bind (&Ekiga::AudioInputCore::remove_device, 
boost::ref (*audioinput_core), _1, _2, _3));
  
- 
 +  /* FIXME: does it really belong here? */
 +  friend_or_foe->add_helper (foe_list);
-   contact_core->add_contact_decorator (foe_list);
 +
  #if DEBUG_STARTUP
    std::cout << "Here is what ekiga is made of for this run :" << std::endl;
    service_core->dump (std::cout);
diff --cc lib/engine/gui/gtk-frontend/assistant-window.cpp
index 516c73a,6d73f70..7d9a1cd
--- a/lib/engine/gui/gtk-frontend/assistant-window.cpp
+++ b/lib/engine/gui/gtk-frontend/assistant-window.cpp
@@@ -39,8 -39,10 +39,9 @@@
  #include <glib/gi18n.h>
  
  #include "services.h"
 -#include "account-core.h"
  #include "account.h"
  
+ #include "gm-entry.h"
  #include "platform.h"
  #include "assistant-window.h"
  #include "default_devices.h"
diff --cc lib/engine/gui/gtk-frontend/call-window.cpp
index 6ba1afb,04479ec..0dabe40
--- a/lib/engine/gui/gtk-frontend/call-window.cpp
+++ b/lib/engine/gui/gtk-frontend/call-window.cpp
@@@ -117,44 -122,19 +125,36 @@@ struct _EkigaCallWindowPrivat
  
    GtkWidget *video_widget;
    bool fullscreen;
+   bool dead;
+   bool bad_connection;
  
-   GtkWidget *call_frame;
-   GtkWidget *camera_image;
- 
-   GtkWidget *main_menu;
    GtkWidget *call_panel_toolbar;
-   GtkWidget *pick_up_button;
-   GtkWidget *hang_up_button;
-   GtkWidget *hold_button;
-   GtkWidget *audio_settings_button;
-   GtkWidget *video_settings_button;
 +  GtkWidget *blacklist_button;
 +
 +  GtkWidget *audio_settings_window;
 +  GtkWidget *audio_input_volume_frame;
 +  GtkWidget *audio_output_volume_frame;
 +  GtkWidget *input_signal;
 +  GtkWidget *output_signal;
 +#if GTK_CHECK_VERSION (3, 0, 0)
 +  GtkAdjustment *adj_input_volume;
 +  GtkAdjustment *adj_output_volume;
 +#else
 +  GtkObject *adj_input_volume;
 +  GtkObject *adj_output_volume;
 +#endif
 +#ifndef WIN32
 +  GC gc;
 +#endif
+   GtkWidget *settings_button;
  
-   unsigned int levelmeter_timeout_id;
    unsigned int timeout_id;
  
-   GtkWidget *video_settings_window;
-   GtkWidget *video_settings_frame;
-   GtkAdjustment *adj_whiteness;
-   GtkAdjustment *adj_brightness;
-   GtkAdjustment *adj_colour;
-   GtkAdjustment *adj_contrast;
+   GtkWidget *info_bar;
+ 
+   /* Audio and video settings */
+   int settings[MAX_SETTINGS];
+   GtkWidget *settings_range[MAX_SETTINGS];
  
    std::string transmitted_video_codec;
    std::string transmitted_audio_codec;
@@@ -180,48 -155,21 +175,42 @@@ enum 
    CHANNEL_LAST
  };
  
- static bool notify_has_actions (EkigaCallWindow* cw);
  
- static void show_extended_video_window_cb (GtkWidget *widget,
+ static void show_extended_video_window_cb (G_GNUC_UNUSED GSimpleAction *action,
+                                            G_GNUC_UNUSED GVariant *parameter,
                                             gpointer data);
  
- static void fullscreen_changed_cb (GtkWidget *widget,
+ static void fullscreen_changed_cb (G_GNUC_UNUSED GSimpleAction *action,
+                                    G_GNUC_UNUSED GVariant *parameter,
                                     gpointer data);
  
 +static void pick_up_call_cb (GtkWidget * /*widget*/,
 +                             gpointer data);
 +
 +static void hang_up_call_cb (GtkWidget * /*widget*/,
 +                             gpointer data);
 +
 +static void hold_current_call_cb (GtkWidget *widget,
 +                                  gpointer data);
 +
 +static void blacklist_cb (GtkWidget* widget,
 +                        gpointer data);
 +
 +static void toggle_audio_stream_pause_cb (GtkWidget * /*widget*/,
 +                                          gpointer data);
 +
 +static void toggle_video_stream_pause_cb (GtkWidget * /*widget*/,
 +                                          gpointer data);
 +
 +static void transfer_current_call_cb (GtkWidget *widget,
 +                                      gpointer data);
 +
- static void audio_volume_changed_cb (GtkAdjustment * /*adjustment*/,
-                                      gpointer data);
- 
- static void audio_volume_window_shown_cb (GtkWidget * /*widget*/,
-                                           gpointer data);
- 
- static void audio_volume_window_hidden_cb (GtkWidget * /*widget*/,
+ static void show_call_devices_settings_cb (G_GNUC_UNUSED GSimpleAction *action,
+                                            G_GNUC_UNUSED GVariant *parameter,
                                             gpointer data);
  
- static void video_settings_changed_cb (GtkAdjustment * /*adjustment*/,
-                                        gpointer data);
- 
- static gboolean on_signal_level_refresh_cb (gpointer self);
+ static void call_devices_settings_changed_cb (GtkRange *range,
+                                               gpointer data);
  
  static void on_videooutput_device_opened_cb (Ekiga::VideoOutputManager & /* manager */,
                                               Ekiga::VideoOutputManager::VideoView type,
@@@ -451,116 -401,16 +442,36 @@@ fullscreen_changed_cb (G_GNUC_UNUSED GS
    ekiga_call_window_toggle_fullscreen (EKIGA_CALL_WINDOW (data));
  }
  
- static void
- pick_up_call_cb (GtkWidget * /*widget*/,
-                  gpointer data)
- {
-   EkigaCallWindow *cw = EKIGA_CALL_WINDOW (data);
- 
-   if (cw->priv->current_call)
-     cw->priv->current_call->answer ();
- }
- 
- static void
- hang_up_call_cb (GtkWidget * /*widget*/,
-                  gpointer data)
- {
-   EkigaCallWindow *cw = EKIGA_CALL_WINDOW (data);
- 
-   if (cw->priv->current_call)
-     cw->priv->current_call->hang_up ();
- }
- 
- 
- static void
- hold_current_call_cb (G_GNUC_UNUSED GtkWidget *widget,
-                       gpointer data)
- {
-   EkigaCallWindow *cw = EKIGA_CALL_WINDOW (data);
- 
-   if (cw->priv->current_call)
-     cw->priv->current_call->toggle_hold ();
- }
- 
 +
 +static void
 +blacklist_cb (G_GNUC_UNUSED GtkWidget *widget,
 +            gpointer data)
 +{
 +  EkigaCallWindow *cw = EKIGA_CALL_WINDOW (data);
 +
 +  if (cw->priv->current_call) {
 +
 +    const std::string uri = cw->priv->current_call->get_remote_uri ();
 +    Ekiga::FriendOrFoe::Identification id = cw->priv->friend_or_foe->decide ("call", uri);
 +    if (id == Ekiga::FriendOrFoe::Unknown) {
 +
 +      cw->priv->foe_list->add_foe (uri);
 +      gtk_widget_set_sensitive (GTK_WIDGET (cw->priv->blacklist_button), false);
 +    }
 +  }
 +}
 +
- static void
- toggle_audio_stream_pause_cb (GtkWidget * /*widget*/,
-                               gpointer data)
- {
-   EkigaCallWindow *cw = EKIGA_CALL_WINDOW (data);
- 
-   if (cw->priv->current_call)
-     cw->priv->current_call->toggle_stream_pause (Ekiga::Call::Audio);
- }
- 
- static void
- toggle_video_stream_pause_cb (GtkWidget * /*widget*/,
-                               gpointer data)
- {
-   EkigaCallWindow *cw = EKIGA_CALL_WINDOW (data);
- 
-   if (cw->priv->current_call)
-     cw->priv->current_call->toggle_stream_pause (Ekiga::Call::Video);
- }
- 
- static void
- transfer_current_call_cb (G_GNUC_UNUSED GtkWidget *widget,
-                           gpointer data)
- {
-   EkigaCallWindow *cw = EKIGA_CALL_WINDOW (data);
- 
-   g_return_if_fail (data != NULL);
-   ekiga_call_window_transfer_dialog_run (EKIGA_CALL_WINDOW (cw), GTK_WIDGET (data), NULL);
- }
- 
- static void
- audio_volume_changed_cb (GtkAdjustment * /*adjustment*/,
-                          gpointer data)
- {
-   EkigaCallWindow *cw = EKIGA_CALL_WINDOW (data);
- 
-   cw->priv->audiooutput_core->set_volume (Ekiga::primary, (unsigned) gtk_adjustment_get_value 
(GTK_ADJUSTMENT (cw->priv->adj_output_volume)));
-   cw->priv->audioinput_core->set_volume ((unsigned) gtk_adjustment_get_value (GTK_ADJUSTMENT 
(cw->priv->adj_input_volume)));
- }
- 
- static void
- audio_volume_window_shown_cb (GtkWidget * /*widget*/,
-                               gpointer data)
- {
-   EkigaCallWindow *cw = EKIGA_CALL_WINDOW (data);
- 
-   cw->priv->audioinput_core->set_average_collection (true);
-   cw->priv->audiooutput_core->set_average_collection (true);
-   cw->priv->levelmeter_timeout_id = g_timeout_add_full (G_PRIORITY_DEFAULT_IDLE, 50, 
on_signal_level_refresh_cb, data, NULL);
- }
 +
  static void
- audio_volume_window_hidden_cb (GtkWidget * /*widget*/,
+ show_call_devices_settings_cb (G_GNUC_UNUSED GSimpleAction *action,
+                                G_GNUC_UNUSED GVariant *parameter,
                                 gpointer data)
  {
-   EkigaCallWindow *cw = EKIGA_CALL_WINDOW (data);
+   g_return_if_fail (EKIGA_IS_CALL_WINDOW (data));
+   EkigaCallWindow *self = EKIGA_CALL_WINDOW (data);
  
-   g_source_remove (cw->priv->levelmeter_timeout_id);
-   cw->priv->audioinput_core->set_average_collection (false);
-   cw->priv->audiooutput_core->set_average_collection (false);
+   gtk_widget_show_all (gm_call_window_build_settings_popover (self,
+                                                               self->priv->settings_button));
  }
  
  static void
@@@ -958,40 -776,17 +837,25 @@@ on_setup_call_cb (boost::shared_ptr<Eki
    }
    else {
  
-     cw->priv->current_call = call;
-     cw->priv->calling_state = Calling;
+     self->priv->current_call = call;
+     ekiga_call_window_update_calling_state (self, Calling);
+     ekiga_call_window_update_title (self, Calling, call->get_remote_uri ());
+     ekiga_call_window_update_header_bar_actions (self, Calling);
    }
  
 +  { // do we know about this contact already?
-     const std::string uri = cw->priv->current_call->get_remote_uri ();
-     Ekiga::FriendOrFoe::Identification id = cw->priv->friend_or_foe->decide ("call", uri);
++    const std::string uri = self->priv->current_call->get_remote_uri ();
++    Ekiga::FriendOrFoe::Identification id = self->priv->friend_or_foe->decide ("call", uri);
 +    if (id == Ekiga::FriendOrFoe::Unknown)
-       gtk_widget_set_sensitive (GTK_WIDGET (cw->priv->blacklist_button), true);
++      gtk_widget_set_sensitive (GTK_WIDGET (self->priv->blacklist_button), true);
 +    else
-       gtk_widget_set_sensitive (GTK_WIDGET (cw->priv->blacklist_button), false);
++      gtk_widget_set_sensitive (GTK_WIDGET (self->priv->blacklist_button), false);
 +  }
  
-   gtk_window_set_title (GTK_WINDOW (cw), call->get_remote_uri ().c_str ());
- 
-   if (call->is_outgoing ())
-     ekiga_call_window_set_status (cw, _("Calling %s..."), call->get_remote_uri ().c_str ());
- 
-   ekiga_call_window_update_calling_state (cw, cw->priv->calling_state);
+   conn = call->questions.connect (boost::bind (&on_handle_questions, _1, (gpointer) self));
+   self->priv->connections.add (conn);
  }
  
- static void
- on_ringing_call_cb (G_GNUC_UNUSED boost::shared_ptr<Ekiga::CallManager> manager,
-                     G_GNUC_UNUSED boost::shared_ptr<Ekiga::Call>  call,
-                     gpointer self)
- {
-   EkigaCallWindow *cw = EKIGA_CALL_WINDOW (self);
- 
-   g_return_if_fail (cw);
- 
-   cw->priv->calling_state = Ringing;
- 
-   ekiga_call_window_update_calling_state (cw, cw->priv->calling_state);
- }
  
  static void
  on_established_call_cb (boost::shared_ptr<Ekiga::CallManager>  /*manager*/,
@@@ -2412,36 -1728,35 +1796,37 @@@ ekiga_call_window_class_init (EkigaCall
  }
  
  GtkWidget *
- call_window_new (Ekiga::ServiceCore & core)
+ call_window_new (GmApplication *app)
  {
-   EkigaCallWindow *cw;
+   EkigaCallWindow *self;
  
-   cw = EKIGA_CALL_WINDOW (g_object_new (EKIGA_TYPE_CALL_WINDOW,
-                                         "key", USER_INTERFACE ".call-window",
-                                         "hide_on_delete", false,
-                                         "hide_on_esc", false, NULL));
+   g_return_val_if_fail (GM_IS_APPLICATION (app), NULL);
  
-   cw->priv->libnotify = core.get ("libnotify");
-   cw->priv->videoinput_core = core.get<Ekiga::VideoInputCore> ("videoinput-core");
-   cw->priv->videooutput_core = core.get<Ekiga::VideoOutputCore> ("videooutput-core");
-   cw->priv->audioinput_core = core.get<Ekiga::AudioInputCore> ("audioinput-core");
-   cw->priv->audiooutput_core = core.get<Ekiga::AudioOutputCore> ("audiooutput-core");
-   cw->priv->call_core = core.get<Ekiga::CallCore> ("call-core");
-   cw->priv->friend_or_foe = core.get<Ekiga::FriendOrFoe> ("friend-or-foe");
-   cw->priv->foe_list = core.get<Ekiga::FoeList> ("foe-list");
+   self = EKIGA_CALL_WINDOW (g_object_new (EKIGA_TYPE_CALL_WINDOW,
+                                           "application", GTK_APPLICATION (app),
+                                           "key", USER_INTERFACE ".call-window",
+                                           "hide_on_delete", false,
+                                           "hide_on_esc", false, NULL));
+   Ekiga::ServiceCorePtr core = gm_application_get_core (app);
  
-   ekiga_call_window_connect_engine_signals (cw);
+   self->priv->videoinput_core = core->get<Ekiga::VideoInputCore> ("videoinput-core");
+   self->priv->videooutput_core = core->get<Ekiga::VideoOutputCore> ("videooutput-core");
+   self->priv->audioinput_core = core->get<Ekiga::AudioInputCore> ("audioinput-core");
+   self->priv->audiooutput_core = core->get<Ekiga::AudioOutputCore> ("audiooutput-core");
+   self->priv->call_core = core->get<Ekiga::CallCore> ("call-core");
++  self->priv->friend_or_foe = core->get<Ekiga::FriendOrFoe> ("friend-or-foe");
++  self->priv->foe_list = core->get<Ekiga::FoeList> ("foe-list");
  
-   ekiga_call_window_init_gui (cw);
+   ekiga_call_window_init_gui (self);
  
-   g_settings_bind (cw->priv->video_display_settings->get_g_settings (),
+   g_settings_bind (self->priv->video_display_settings->get_g_settings (),
                     "stay-on-top",
-                    cw,
+                    self,
                     "stay_on_top",
                     G_SETTINGS_BIND_DEFAULT);
-   g_settings_bind (cw->priv->video_display_settings->get_g_settings (),
+   g_settings_bind (self->priv->video_display_settings->get_g_settings (),
                     "enable-pip",
-                    cw->priv->video_widget,
+                    self->priv->video_widget,
                     "secondary_stream_display",
                     G_SETTINGS_BIND_DEFAULT);
  
diff --cc lib/engine/gui/gtk-frontend/chat-window.cpp
index 8e83805,9d56063..6b9651c
--- a/lib/engine/gui/gtk-frontend/chat-window.cpp
+++ b/lib/engine/gui/gtk-frontend/chat-window.cpp
@@@ -40,10 -38,10 +40,12 @@@
  #include <gdk/gdkkeysyms.h>
  #include <glib/gi18n.h>
  
 +#include "menu-builder-gtk.h"
 +
  #include "chat-core.h"
+ #include "audiooutput-core.h"
  #include "notification-core.h"
+ #include "ekiga-settings.h"
  
  #include "form-dialog-gtk.h"
  #include "scoped-connections.h"
@@@ -55,11 -53,13 +57,12 @@@
  struct _ChatWindowPrivate
  {
    boost::shared_ptr<Ekiga::NotificationCore> notification_core;
+   boost::shared_ptr<Ekiga::AudioOutputCore> audiooutput_core;
    Ekiga::scoped_connections connections;
 +  boost::signals2::connection visible_conversation_connection;
  
 -  GtkWidget* notebook;
 -
 -  /* GSettings */
 -  boost::shared_ptr<Ekiga::Settings> sound_events_settings;
 +  GtkWidget* stack;
 +  GtkWidget* gear;
  };
  
  enum {
@@@ -93,40 -110,47 +96,35 @@@ static void on_some_conversation_user_r
  
  static void show_chat_window_cb (ChatWindow *self);
  
- /* internal api (declaration) */
- 
- static void chat_window_update_menu (ChatWindow* self,
-                                    Ekiga::ConversationPtr conversation);
 -/* DESCRIPTION  :  This callback is called when the chat window alerts about
 - *                 unread messages
 - * BEHAVIOR     :  Plays a sound (if enabled)
 - * PRE          :  /
 - */
 -static void on_chat_unread_alert (GtkWidget*,
 -                                gpointer);
 -
 -
 -/* helper (implementation) */
  
 +/* helpers (implementation) */
- 
  static void
 -update_unread (ChatWindow* self)
 +on_unread_count_updated (ConversationPage* page,
 +                       gpointer data)
  {
 +  ChatWindow* self = (ChatWindow*)data;
    guint unread_count = 0;
 -  GtkWidget* page = NULL;
 -  GtkWidget* hbox = NULL;
 -  GtkWidget* label = NULL;
 -  gchar *info = NULL;
 -
 -  for (gint ii = 0;
 -       ii < gtk_notebook_get_n_pages (GTK_NOTEBOOK (self->priv->notebook)) ;
 -       ii++) {
 -
 -    page
 -      = gtk_notebook_get_nth_page (GTK_NOTEBOOK (self->priv->notebook), ii);
 -    hbox = gtk_notebook_get_tab_label (GTK_NOTEBOOK (self->priv->notebook),
 -                                     page);
 -    label = (GtkWidget*)g_object_get_data (G_OBJECT (hbox), "label-widget");
 -    unread_count
 -      = unread_count
 -      + GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (label), "unread-count"));
  
 +  gtk_container_child_set (GTK_CONTAINER (self->priv->stack), GTK_WIDGET (page),
 +                         "title", conversation_page_get_title (page),
 +                         NULL);
 +
 +  GList* pages = gtk_container_get_children (GTK_CONTAINER (self->priv->stack));
 +
 +  for (GList* ptr = pages; ptr != NULL; ptr = ptr->next) {
 +
 +    unread_count += conversation_page_get_unread_count ((ConversationPage*)ptr->data);
    }
  
 +  g_list_free (pages);
 +
    g_signal_emit (self, signals[UNREAD_COUNT], 0, unread_count);
 +  g_signal_emit (self, signals[UNREAD_ALERT], 0, NULL);
  
    if (unread_count > 0) {
 -    info = g_strdup_printf (ngettext ("You have %d unread text message",
 -                                      "You have %d unread text messages",
 -                                      unread_count), unread_count);
 +    gchar* info = g_strdup_printf (ngettext ("You have %d unread text message",
 +                                           "You have %d unread text messages",
 +                                           unread_count), unread_count);
      boost::shared_ptr<Ekiga::Notification> notif (new Ekiga::Notification (Ekiga::Notification::Warning, 
info, "", _("Read"), boost::bind (show_chat_window_cb, self)));
      self->priv->notification_core->push_notification (notif);
      g_free (info);
@@@ -135,20 -159,102 +133,19 @@@
  
  /* signal callbacks (implementations) */
  
 -static bool on_handle_questions (ChatWindow* self,
 -                               Ekiga::FormRequestPtr request)
 -{
 -  GtkWidget *parent = gtk_widget_get_toplevel (GTK_WIDGET (self));
 -  FormDialog dialog (request, parent);
 -
 -  dialog.run ();
 -
 -  return true;
 -}
 -
 -static void
 -on_close_button_clicked (GtkButton* button,
 -                       gpointer data)
 -{
 -  ChatWindow* self = (ChatWindow*)data;
 -  GtkWidget* page = NULL;
 -  gint num = 0;
 -
 -  page = (GtkWidget*)g_object_get_data (G_OBJECT (button), "page-widget");
 -  num = gtk_notebook_page_num (GTK_NOTEBOOK (self->priv->notebook), page);
 -
 -  gtk_notebook_remove_page (GTK_NOTEBOOK (self->priv->notebook), num);
 -
 -  if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (self->priv->notebook)) == 0)
 -    gtk_widget_hide (GTK_WIDGET (self));
 -}
 -
  static void
 -on_escaped (GtkWidget */*widget*/,
 -            gpointer data)
 +on_visible_conversation_updated (ChatWindow* self)
  {
 -  ChatWindow* self = (ChatWindow*)data;
 -  gint num = 0;
 +  self->priv->visible_conversation_connection.disconnect ();
  
 -  num = gtk_notebook_get_current_page (GTK_NOTEBOOK (self->priv->notebook));
 -  gtk_notebook_remove_page (GTK_NOTEBOOK (self->priv->notebook), num);
 +  GtkWidget* page = gtk_stack_get_visible_child (GTK_STACK (self->priv->stack));
  
 -  if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (self->priv->notebook)) == 0)
 -    gtk_widget_hide (GTK_WIDGET (self));
 -}
 +  if (IS_CONVERSATION_PAGE (page)) {
  
 -static void
 -on_switch_page (G_GNUC_UNUSED GtkNotebook* notebook,
 -              G_GNUC_UNUSED gpointer page_,
 -              guint num,
 -              gpointer data)
 -{
 -  ChatWindow* self = (ChatWindow*)data;
 -  GtkWidget* page = NULL;
 -  GtkWidget* hbox = NULL;
 -  GtkWidget* label = NULL;
 -
 -  page = gtk_notebook_get_nth_page (GTK_NOTEBOOK (self->priv->notebook), num);
 -  hbox = gtk_notebook_get_tab_label (GTK_NOTEBOOK (self->priv->notebook),
 -                                   page);
 -  label = (GtkWidget*)g_object_get_data (G_OBJECT (hbox), "label-widget");
 -  gtk_label_set_text (GTK_LABEL (label),
 -                    (const gchar*)g_object_get_data (G_OBJECT (label),
 -                                                     "base-title"));
 -  g_object_set_data (G_OBJECT (label), "unread-count",
 -                   GUINT_TO_POINTER (0));
 -
 -  update_unread (self);
 -
 -  gtk_widget_grab_focus (page);
 -}
 +    Ekiga::ConversationPtr conversation = conversation_page_get_conversation (CONVERSATION_PAGE (page));
  
 -static gboolean
 -on_focus_in_event (G_GNUC_UNUSED GtkWidget* widget,
 -                 G_GNUC_UNUSED GdkEventFocus* event,
 -                 gpointer data)
 -{
 -  ChatWindow* self = (ChatWindow*)data;
 -  gint num;
 -  GtkWidget* page = NULL;
 -  GtkWidget* hbox = NULL;
 -  GtkWidget* label = NULL;
 -
 -  num = gtk_notebook_get_current_page (GTK_NOTEBOOK (self->priv->notebook));
 -  if (num != -1) { /* the notebook may be empty */
 -
 -    page = gtk_notebook_get_nth_page (GTK_NOTEBOOK (self->priv->notebook), num);
 -    hbox = gtk_notebook_get_tab_label (GTK_NOTEBOOK (self->priv->notebook),
 -                                     page);
 -    label = (GtkWidget*)g_object_get_data (G_OBJECT (hbox), "label-widget");
 -    gtk_label_set_text (GTK_LABEL (label),
 -                      (const gchar*)g_object_get_data (G_OBJECT (label),
 -                                                     "base-title"));
 -    g_object_set_data (G_OBJECT (label), "unread-count",
 -                     GUINT_TO_POINTER (0));
 -
 -    update_unread (self);
 +    self->priv->visible_conversation_connection = conversation->updated.connect (boost::bind 
(&on_visible_conversation_updated, self));
-     chat_window_update_menu (self, conversation);
    }
 -
 -  return FALSE;
  }
  
  static void
@@@ -221,9 -405,24 +218,8 @@@ show_chat_window_cb (ChatWindow *self
    gtk_window_present (GTK_WINDOW (self));
  }
  
 -static void
 -on_chat_unread_alert (G_GNUC_UNUSED GtkWidget* widget,
 -                    gpointer data)
 -{
 -  ChatWindow *self = CHAT_WINDOW (data);
 -
 -  g_return_if_fail (self != NULL);
 -  if (!self->priv->sound_events_settings->get_bool ("enable-new-message-sound"))
 -    return;
 -
 -  std::string file_name_string = self->priv->sound_events_settings->get_string ("new-message-sound");
 -
 -  if (!file_name_string.empty ())
 -    self->priv->audiooutput_core->play_file (file_name_string);
 -}
 -
  
  /* GObject code */
- 
  static void
  chat_window_finalize (GObject* obj)
  {
@@@ -269,72 -468,53 +265,58 @@@ chat_window_init (ChatWindow* self
  {
    /* we can't do much here since we get the Chat as reference... */
    gtk_window_set_title (GTK_WINDOW (self), _("Chat Window"));
- }
- 
- /* internal api (implementation) */
- 
- static void chat_window_update_menu (ChatWindow* self,
-                                    Ekiga::ConversationPtr conversation)
- {
-   MenuBuilderGtk builder;
- 
-   conversation->populate_menu (builder);
  
-   if (!builder.empty ()) {
- 
-     gtk_widget_show_all (builder.menu);
-     gtk_menu_button_set_popup (GTK_MENU_BUTTON (self->priv->gear),
-                              builder.menu);
-   }
-   g_object_ref_sink (builder.menu);
+   self->priv = new ChatWindowPrivate;
  }
  
- /* public api */
  
+ /* Public API */
  GtkWidget*
- chat_window_new (Ekiga::ServiceCore& core,
-                const char* key)
+ chat_window_new (GmApplication *app)
  {
    ChatWindow* self = NULL;
 -  GtkAccelGroup *accel = NULL;
  
-   self = (ChatWindow*)g_object_new (CHAT_WINDOW_TYPE,
-                                   "key", key,
-                                     "hide_on_esc", FALSE,
-                                   NULL);
+   g_return_val_if_fail (GM_IS_APPLICATION (app), NULL);
  
-   self->priv = new ChatWindowPrivate;
+   Ekiga::ServiceCorePtr core = gm_application_get_core (app);
  
+   self = (ChatWindow*)g_object_new (CHAT_WINDOW_TYPE,
+                                     "application", GTK_APPLICATION (app),
+                                     "key", USER_INTERFACE ".chat-window",
+                                   NULL);
 -
 -  self->priv->sound_events_settings =
 -    boost::shared_ptr<Ekiga::Settings> (new Ekiga::Settings (SOUND_EVENTS_SCHEMA));
    self->priv->notification_core =
-     core.get<Ekiga::NotificationCore>("notification-core");
+     core->get<Ekiga::NotificationCore>("notification-core");
+   self->priv->audiooutput_core =
+     core->get<Ekiga::AudioOutputCore>("audiooutput-core");
  
 -  self->priv->notebook = gtk_notebook_new ();
 -  gtk_container_add (GTK_CONTAINER (self), self->priv->notebook);
 -  gtk_widget_show (self->priv->notebook);
 -
 -  accel = gtk_accel_group_new ();
 -  gtk_window_add_accel_group (GTK_WINDOW (self), accel);
 -  gtk_accel_group_connect (accel, GDK_KEY_Escape, (GdkModifierType) 0, GTK_ACCEL_LOCKED,
 -                           g_cclosure_new_swap (G_CALLBACK (on_escaped), (gpointer) self, NULL));
 -  g_object_unref (accel);
 -
 -  g_signal_connect (self, "focus-in-event",
 -                  G_CALLBACK (on_focus_in_event), self);
 -  g_signal_connect (self->priv->notebook, "switch-page",
 -                  G_CALLBACK (on_switch_page), self);
 -  g_signal_connect (self, "unread-alert",
 -                    G_CALLBACK (on_chat_unread_alert), self);
 +  GtkWidget* vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
 +  gtk_container_add (GTK_CONTAINER (self), vbox);
 +  gtk_widget_show (vbox);
 +
 +  GtkWidget* hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2);
 +  gtk_container_add (GTK_CONTAINER (vbox), hbox);
 +  gtk_widget_show (hbox);
 +
 +  self->priv->gear = gtk_menu_button_new ();
 +  gtk_box_pack_start (GTK_BOX (hbox), self->priv->gear,
 +                    FALSE, FALSE, 0);
 +  gtk_widget_show (self->priv->gear);
 +
 +  GtkWidget* switcher = gtk_stack_switcher_new ();
 +  gtk_box_pack_start (GTK_BOX (hbox), switcher,
 +                    FALSE, TRUE, 0);
 +  gtk_widget_show (switcher);
 +
 +  self->priv->stack = gtk_stack_new ();
 +  gtk_stack_switcher_set_stack (GTK_STACK_SWITCHER (switcher), GTK_STACK (self->priv->stack));
 +  gtk_box_pack_start (GTK_BOX (vbox), self->priv->stack,
 +                    TRUE, TRUE, 0);
 +  gtk_widget_show (self->priv->stack);
 +  g_signal_connect (self->priv->stack, "notify::visible-child",
 +                  G_CALLBACK (on_visible_conversation_changed), self);
  
    boost::shared_ptr<Ekiga::ChatCore> chat_core =
-     core.get<Ekiga::ChatCore> ("chat-core");
+     core->get<Ekiga::ChatCore> ("chat-core");
    self->priv->connections.add (chat_core->dialect_added.connect (boost::bind (&on_dialect_added, self, 
_1)));
    self->priv->connections.add (chat_core->questions.connect (boost::bind (&on_handle_questions, self, _1)));
    chat_core->visit_dialects (boost::bind (&on_dialect_added, self, _1));
diff --cc lib/engine/gui/gtk-frontend/conversation-page.cpp
index 6975d77,0000000..ea1d7ee
mode 100644,000000..100644
--- a/lib/engine/gui/gtk-frontend/conversation-page.cpp
+++ b/lib/engine/gui/gtk-frontend/conversation-page.cpp
@@@ -1,206 -1,0 +1,196 @@@
 +
 +/* Ekiga -- A VoIP and Video-Conferencing application
 + * Copyright (C) 2000-2009 Damien Sandras <dsandras seconix com>
 + *
 + * This program is free software; you can redistribute it and/or modify
 + * it under the terms of the GNU General Public License as published by
 + * the Free Software Foundation; either version 2 of the License, or
 + * (at your option) any later version.
 + *
 + * This program is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 + * GNU General Public License for more details.
 + *
 + * You should have received a copy of the GNU General Public License
 + * along with this program; if not, write to the Free Software Foundation,
 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
 + *
 + *
 + * Ekiga is licensed under the GPL license and as a special exception,
 + * you have permission to link or otherwise combine this program with the
 + * programs OPAL, OpenH323 and PWLIB, and distribute the combination,
 + * without applying the requirements of the GNU GPL to the OPAL, OpenH323
 + * and PWLIB programs, as long as you do follow the requirements of the
 + * GNU GPL for all the rest of the software thus combined.
 + */
 +
 +
 +/*
 + *                        multiple-chat-page.cpp  -  description
 + *                         --------------------------------
 + *   begin                : written in july 2008 by Julien Puydt
 + *   copyright            : (C) 2008 by Julien Puydt
 + *   description          : Declaration of a page displaying a Conversation
 + *
 + */
 +
 +#include "conversation-page.h"
 +#include "chat-area.h"
- #include "heap-view.h"
 +
 +#include "scoped-connections.h"
 +
 +struct _ConversationPagePrivate {
 +
 +  Ekiga::ConversationPtr conversation;
 +  Ekiga::scoped_connections connections;
 +  GtkWidget* area;
-   GtkWidget* heapview;
 +  GtkWidget* header;
 +  gchar* title;
 +};
 +
 +enum {
 +  UPDATED_SIGNAL,
 +  LAST_SIGNAL
 +};
 +
 +static guint signals[LAST_SIGNAL] = {0,};
 +
 +G_DEFINE_TYPE (ConversationPage, conversation_page, GTK_TYPE_BOX);
 +
 +static void
 +on_conversation_updated (ConversationPage* self)
 +{
 +  g_signal_emit (self, signals[UPDATED_SIGNAL], 0);
 +}
 +
 +static void
 +on_page_grab_focus (GtkWidget* widget,
 +                  G_GNUC_UNUSED gpointer data)
 +{
 +  ConversationPage* self = (ConversationPage*)widget;
 +
 +  gtk_widget_grab_focus (self->priv->area);
 +}
 +
 +static void
 +conversation_page_update_title_and_status (ConversationPage* self)
 +{
 +  g_free (self->priv->title);
 +  guint unread_count = self->priv->conversation->get_unread_messages_count ();
 +  if (unread_count > 0) {
 +
 +    self->priv->title = g_strdup_printf ("[%d] %s",
 +                                       unread_count,
 +                                       self->priv->conversation->get_title ().c_str ());
 +  } else {
 +
 +    self->priv->title = g_strdup_printf ("%s",
 +                                       self->priv->conversation->get_title ().c_str ());
 +  }
 +  gtk_header_bar_set_title (GTK_HEADER_BAR (self->priv->header), self->priv->title);
 +  gtk_header_bar_set_subtitle (GTK_HEADER_BAR (self->priv->header),
 +                             self->priv->conversation->get_status ().c_str ());
 +}
 +
 +static void
 +conversation_page_finalize (GObject* obj)
 +{
 +  ConversationPage* self = (ConversationPage*)obj;
 +
 +  g_free (self->priv->title);
 +  delete self->priv;
 +
 +  G_OBJECT_CLASS (conversation_page_parent_class)->finalize (obj);
 +}
 +
 +static void
 +conversation_page_init (ConversationPage* self)
 +{
 +  self->priv = new ConversationPagePrivate;
 +
 +  g_signal_connect (self, "grab-focus",
 +                    G_CALLBACK (on_page_grab_focus), NULL);
 +}
 +
 +static void
 +conversation_page_class_init (ConversationPageClass* klass)
 +{
 +  GObjectClass* gobject_class = G_OBJECT_CLASS (klass);
 +
 +  gobject_class->finalize = conversation_page_finalize;
 +
 +  signals[UPDATED_SIGNAL] =
 +    g_signal_new ("updated", G_OBJECT_CLASS_TYPE (gobject_class),
 +                G_SIGNAL_RUN_LAST,
 +                G_STRUCT_OFFSET (ConversationPageClass, updated),
 +                NULL, NULL,
 +                g_cclosure_marshal_VOID__VOID,
 +                G_TYPE_NONE, 0);
 +}
 +
 +/* implementation of the public api */
 +
 +GtkWidget*
 +conversation_page_new (Ekiga::ConversationPtr conversation)
 +{
 +  ConversationPage* result = NULL;
 +  GtkWidget* header = NULL;
 +  GtkWidget* box = NULL;
 +  GtkWidget* area = NULL;
-   GtkWidget* heapview = NULL;
 +
 +  result = (ConversationPage*)g_object_new (TYPE_CONVERSATION_PAGE,
 +                                          "orientation", GTK_ORIENTATION_VERTICAL,
 +                                          NULL);
 +
 +  result->priv->conversation = conversation;
 +  result->priv->title = NULL;
 +
 +  result->priv->connections.add (conversation->updated.connect (boost::bind (&on_conversation_updated, 
result)));
 +
 +  header = gtk_header_bar_new ();
 +  result->priv->header = header;
 +  gtk_box_pack_start (GTK_BOX (result), header,
 +                    FALSE, FALSE, 2);
 +  gtk_widget_show (header);
 +
 +  box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2);
 +  gtk_box_pack_start (GTK_BOX (result), box,
 +                    TRUE, TRUE, 2);
 +  gtk_widget_show (box);
 +
 +  area = chat_area_new (conversation);
 +  result->priv->area = area;
 +  gtk_box_pack_start (GTK_BOX (box), area,
 +                    TRUE, TRUE, 2);
 +  gtk_widget_show (area);
 +
-   heapview = heap_view_new (conversation->get_heap());
- 
-   result->priv->heapview = heapview;
-   gtk_box_pack_start (GTK_BOX (box), heapview,
-                     TRUE, TRUE, 2);
-   gtk_widget_show (heapview);
- 
 +  conversation_page_update_title_and_status (result);
 +
 +  return GTK_WIDGET (result);
 +}
 +
 +const gchar*
 +conversation_page_get_title (ConversationPage* page)
 +{
 +  g_return_val_if_fail (IS_CONVERSATION_PAGE (page), NULL);
 +
 +  return page->priv->title;
 +}
 +
 +guint
 +conversation_page_get_unread_count (ConversationPage* page)
 +{
 +  g_return_val_if_fail (IS_CONVERSATION_PAGE (page), 0);
 +
 +  return page->priv->conversation->get_unread_messages_count ();
 +}
 +
 +Ekiga::ConversationPtr
 +conversation_page_get_conversation (ConversationPage* page)
 +{
 +  g_return_val_if_fail (IS_CONVERSATION_PAGE (page), Ekiga::ConversationPtr());
 +
 +  return page->priv->conversation;
 +
 +}
diff --cc lib/engine/gui/gtk-frontend/ekiga-app.cpp
index 0000000,fece8a5..f1a5268
mode 000000,100644..100644
--- a/lib/engine/gui/gtk-frontend/ekiga-app.cpp
+++ b/lib/engine/gui/gtk-frontend/ekiga-app.cpp
@@@ -1,0 -1,1037 +1,1036 @@@
+ 
+ /* Ekiga -- A VoIP and Video-Conferencing application
+  * Copyright (C) 2000-2014 Damien Sandras <dsandras seconix com>
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+  * the Free Software Foundation; either version 2 of the License, or
+  * (at your option) any later version.
+  *
+  * This program is distributed in the hope that it will be useful,
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  * GNU General Public License for more details.
+  *
+  * You should have received a copy of the GNU General Public License
+  * along with this program; if not, write to the Free Software Foundation,
+  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+  *
+  *
+  * Ekiga is licensed under the GPL license and as a special exception,
+  * you have permission to link or otherwise combine this program with the
+  * programs OPAL, OpenH323 and PWLIB, and distribute the combination,
+  * without applying the requirements of the GNU GPL to the OPAL, OpenH323
+  * and PWLIB programs, as long as you do follow the requirements of the
+  * GNU GPL for all the rest of the software thus combined.
+  */
+ 
+ 
+ /*
+  *                         ekiga-app.cpp  -  description
+  *                         -----------------------------
+  *   begin                : written in Feb 2014 by Damien Sandras
+  *   copyright            : (c) 2014 by Damien Sandras
+  *   description          : main Ekiga GtkApplication
+  *
+  */
+ 
+ #include <gtk/gtk.h>
+ 
+ #include "config.h"
+ #include "ekiga-settings.h"
+ #include "revision.h"
+ 
+ #include "trigger.h"
+ #include "form-dialog-gtk.h"
+ #include "ekiga-app.h"
+ #include "account-core.h"
+ #include "chat-core.h"
+ #include "contact-core.h"
+ #include "presence-core.h"
+ #include "addressbook-window.h"
+ #include "assistant-window.h"
+ #include "preferences-window.h"
+ #include "call-window.h"
+ #include "chat-window.h"
+ #include "main_window.h"
+ #include "statusicon.h"
+ #include "roster-view-gtk.h"
+ #include "history-source.h"
+ #include "opal-bank.h"
+ #include "book-view-gtk.h"
+ #include "notification-core.h"
+ #include "personal-details.h"
+ #include "audioinput-core.h"
+ #include "audiooutput-core.h"
+ #include "videoinput-core.h"
+ #include "videooutput-core.h"
+ #include "call-core.h"
+ #include "engine.h"
+ #include "runtime.h"
+ #include "platform/platform.h"
+ #include "gactor-menu.h"
+ 
+ #include "gmwindow.h"
+ 
+ #ifdef WIN32
+ #include "platform/winpaths.h"
+ #include <windows.h>
+ #include <shellapi.h>
+ #include <gdk/gdkwin32.h>
+ #include <cstdio>
+ #define WIN32_HELP_DIR "help"
+ #define WIN32_HELP_FILE "index.html"
+ #else
+ #include <signal.h>
+ #include <gdk/gdkx.h>
+ #endif
+ 
+ #ifdef HAVE_DBUS
+ #include "../../../../src/dbus-helper/dbus.h"
+ #endif
+ 
+ #include <glib/gi18n.h>
+ #include <ptlib.h>
 -#include <opal/buildopts.h>
+ 
+ 
+ /*
+  * The GmApplication
+  */
+ struct _GmApplicationPrivate
+ {
+   _GmApplicationPrivate () {}
+ 
+   Ekiga::ServiceCorePtr core;
+ 
+   GtkBuilder *builder;
+   GtkWidget *main_window;
+   GtkWidget *chat_window;
+   GtkWidget *call_window;
+ 
+   boost::shared_ptr<Ekiga::Settings> video_devices_settings;
+ 
+   EkigaDBusComponent *dbus_component;
+ 
+   Ekiga::GActorMenuStore banks_menu;
+   unsigned int banks_actions_count;
+ };
+ 
+ G_DEFINE_TYPE (GmApplication, gm_application, GTK_TYPE_APPLICATION);
+ 
+ static void gm_application_populate_application_menu (GmApplication *app);
+ 
+ static GtkWidget *gm_application_show_call_window (GmApplication *self);
+ 
+ static void on_created_call_cb (boost::shared_ptr<Ekiga::CallManager> manager,
+                                 boost::shared_ptr<Ekiga::Call> call,
+                                 gpointer data);
+ 
+ static bool on_visit_banks_cb (Ekiga::BankPtr bank,
+                                gpointer data);
+ 
+ static bool on_handle_questions_cb (Ekiga::FormRequestPtr request,
+                                     GmApplication *application);
+ 
+ static void on_account_modified_cb (Ekiga::BankPtr bank,
+                                     Ekiga::AccountPtr account,
+                                     GmApplication *app);
+ 
+ static void call_window_destroyed_cb (GtkWidget *widget,
+                                       gpointer data);
+ 
+ static gboolean option_context_parse (GOptionContext *context,
+                                       gchar **arguments,
+                                       GError **error);
+ 
+ static void quit_activated (GSimpleAction *action,
+                             GVariant *parameter,
+                             gpointer app);
+ 
+ static void about_activated (GSimpleAction *action,
+                              GVariant *parameter,
+                              gpointer app);
+ 
+ static void help_activated (GSimpleAction *action,
+                             GVariant *parameter,
+                             gpointer app);
+ 
+ static void window_activated (GSimpleAction *action,
+                               GVariant *parameter,
+                               gpointer app);
+ 
+ static void video_preview_changed (GSettings *settings,
+                                    const gchar *key,
+                                    gpointer data);
+ 
+ static GActionEntry app_entries[] =
+ {
+     { "preferences", window_activated, NULL, NULL, NULL, 0 },
+     { "addressbook", window_activated, NULL, NULL, NULL, 0 },
+     { "help", help_activated, NULL, NULL, NULL, 0 },
+     { "about", about_activated, NULL, NULL, NULL, 0 },
+     { "quit", quit_activated, NULL, NULL, NULL, 0 }
+ };
+ 
+ 
+ /* Private helpers */
+ static void
+ gm_application_populate_application_menu (GmApplication *app)
+ {
+   g_return_if_fail (GM_IS_APPLICATION (app));
+   GMenuModel *app_menu = G_MENU_MODEL (gtk_builder_get_object (app->priv->builder, "appmenu"));
+ 
+   boost::shared_ptr<Ekiga::AccountCore> account_core
+     = app->priv->core->get<Ekiga::AccountCore> ("account-core");
+   g_return_if_fail (account_core);
+ 
+   for (int i = app->priv->banks_menu.size () ;
+        i > 0 ;
+        i--)
+     g_menu_remove (G_MENU (app_menu), 0);
+ 
+   app->priv->banks_menu.clear ();
+   app->priv->banks_actions_count = 0;
+   account_core->visit_banks (boost::bind (&on_visit_banks_cb, _1, (gpointer) app));
+ 
+   for (std::list<Ekiga::GActorMenuPtr>::iterator it = app->priv->banks_menu.begin ();
+        it != app->priv->banks_menu.end ();
+        it++) {
+     g_menu_insert_section (G_MENU (app_menu), 0, NULL, (*it)->get_model ());
+     app->priv->banks_actions_count += (*it)->size ();
+   }
+ }
+ 
+ 
+ static GtkWidget *
+ gm_application_show_call_window (GmApplication *self)
+ {
+   g_return_val_if_fail (GM_IS_APPLICATION (self), NULL);
+ 
+   if (!self->priv->call_window)
+     self->priv->call_window = call_window_new (self);
+ 
+   gtk_window_present (GTK_WINDOW (self->priv->call_window));
+ 
+   g_signal_connect (G_OBJECT (self->priv->call_window), "destroy",
+                     G_CALLBACK (call_window_destroyed_cb), self);
+ 
+   return self->priv->call_window;
+ }
+ 
+ 
+ /* Private callbacks */
+ static void
+ on_created_call_cb (G_GNUC_UNUSED boost::shared_ptr<Ekiga::CallManager> manager,
+                     G_GNUC_UNUSED boost::shared_ptr<Ekiga::Call> call,
+                     gpointer data)
+ {
+   g_return_if_fail (GM_IS_APPLICATION (data));
+ 
+   GmApplication *self = GM_APPLICATION (data);
+ 
+   gm_application_show_call_window (self);
+ }
+ 
+ 
+ static bool
+ on_visit_banks_cb (Ekiga::BankPtr bank,
+                    gpointer data)
+ {
+   g_return_val_if_fail (GM_IS_APPLICATION (data), false);
+ 
+   GmApplication *self = GM_APPLICATION (data);
+ 
+   self->priv->banks_menu.push_back (Ekiga::GActorMenuPtr (new Ekiga::GActorMenu (*bank, "", "app")));
+ 
+   return true;
+ }
+ 
+ 
+ static bool
+ on_handle_questions_cb (Ekiga::FormRequestPtr request,
+                         GmApplication *application)
+ {
+   GtkWidget *window =
+     GTK_WIDGET (gtk_application_get_active_window (GTK_APPLICATION (application)));
+   FormDialog dialog (request, window);
+ 
+   dialog.run ();
+ 
+   return true;
+ }
+ 
+ 
+ static void
+ on_account_modified_cb (G_GNUC_UNUSED Ekiga::BankPtr bank,
+                         G_GNUC_UNUSED Ekiga::AccountPtr account,
+                         GmApplication *app)
+ {
+   g_return_if_fail (GM_IS_APPLICATION (app));
+ 
+   gm_application_populate_application_menu (app);
+ }
+ 
+ 
+ static void
+ call_window_destroyed_cb (G_GNUC_UNUSED GtkWidget *widget,
+                           gpointer data)
+ {
+   g_return_if_fail (GM_IS_APPLICATION (data));
+ 
+   GmApplication *self = GM_APPLICATION (data);
+   if (self->priv->call_window)
+     self->priv->call_window = NULL;
+ }
+ 
+ 
+ static gboolean
+ option_context_parse (GOptionContext *context,
+                       gchar **arguments,
+                       GError **error)
+ {
+   gint argc;
+   gchar **argv;
+   gint i;
+   gboolean ret;
+ 
+   /* We have to make an extra copy of the array, since g_option_context_parse()
+    * assumes that it can remove strings from the array without freeing them.
+    */
+   argc = g_strv_length (arguments);
+   argv = g_new (gchar *, argc);
+   for (i = 0; i < argc; i++)
+     argv[i] = arguments[i];
+ 
+   ret = g_option_context_parse (context, &argc, &argv, error);
+ 
+   g_free (argv);
+ 
+   return ret;
+ }
+ 
+ 
+ static void
+ quit_activated (G_GNUC_UNUSED GSimpleAction *action,
+                 G_GNUC_UNUSED GVariant *parameter,
+                 gpointer app)
+ {
+   g_application_quit (G_APPLICATION (app));
+ }
+ 
+ 
+ static void
+ about_activated (G_GNUC_UNUSED GSimpleAction *action,
+                  G_GNUC_UNUSED GVariant *parameter,
+                  gpointer app)
+ {
+   gm_application_show_about (GM_APPLICATION (app));
+ }
+ 
+ 
+ static void
+ help_activated (G_GNUC_UNUSED GSimpleAction *action,
+                 G_GNUC_UNUSED GVariant *parameter,
+                 gpointer app)
+ {
+   gm_application_show_help (GM_APPLICATION (app), NULL);
+ }
+ 
+ 
+ static void
+ window_activated (GSimpleAction *action,
+                   G_GNUC_UNUSED GVariant *parameter,
+                   gpointer app)
+ {
+   GmApplication *self = GM_APPLICATION (app);
+ 
+   g_return_if_fail (self && self->priv->core);
+ 
+   boost::shared_ptr<Ekiga::AudioInputCore> audio_input_core =
+     self->priv->core->get<Ekiga::AudioInputCore> ("audioinput-core");
+   boost::shared_ptr<Ekiga::AudioOutputCore> audio_output_core =
+     self->priv->core->get<Ekiga::AudioOutputCore> ("audiooutput-core");
+   boost::shared_ptr<Ekiga::VideoInputCore> video_input_core =
+     self->priv->core->get<Ekiga::VideoInputCore> ("videoinput-core");
+   boost::shared_ptr<Ekiga::ContactCore> contact_core =
+     self->priv->core->get<Ekiga::ContactCore> ("contact-core");
+ 
+   if (!g_strcmp0 (g_action_get_name (G_ACTION (action)), "preferences"))
+     gm_application_show_preferences_window (self);
+ 
+   else if (!g_strcmp0 (g_action_get_name (G_ACTION (action)), "addressbook"))
+     gm_application_show_addressbook_window (self);
+ }
+ 
+ 
+ static void
+ video_preview_changed (GSettings *settings,
+                        const gchar *key,
+                        gpointer data)
+ {
+   g_return_if_fail (GM_IS_APPLICATION (data));
+ 
+   GmApplication *self = GM_APPLICATION (data);
+   boost::shared_ptr<Ekiga::VideoInputCore> video_input_core =
+     self->priv->core->get<Ekiga::VideoInputCore> ("videoinput-core");
+ 
+   if (g_settings_get_boolean (settings, key)) {
+     gm_application_show_call_window (self);
+     video_input_core->start_preview ();
+   }
+   else
+     video_input_core->stop_preview ();
+ }
+ 
+ 
+ /* Public api */
+ void
+ ekiga_main (int argc,
+             char **argv)
+ {
+   GmApplication *app = gm_application_new ();
+   g_application_set_inactivity_timeout (G_APPLICATION (app), 10000);
+ 
+   if (g_application_get_is_remote (G_APPLICATION (app))) {
+     g_application_run (G_APPLICATION (app), argc, argv);
+     return;
+   }
+ 
+   Ekiga::ServiceCorePtr core(new Ekiga::ServiceCore);
+ 
+   Ekiga::Runtime::init ();
+   engine_init (core, argc, argv);
+ 
+   gm_application_set_core (app, core);
+ 
+   /* Create the main application window */
+   app->priv->main_window = gm_main_window_new (app);
+   gm_application_show_main_window (app);
+ 
+   app->priv->chat_window = chat_window_new (app);
+   status_icon_new (app);
+ 
+ #ifdef HAVE_DBUS
+   app->priv->dbus_component = ekiga_dbus_component_new (app);
+ #endif
+ 
+   boost::shared_ptr<Ekiga::Settings> general_settings (new Ekiga::Settings (GENERAL_SCHEMA));
+   const int schema_version = MAJOR_VERSION * 1000 + MINOR_VERSION * 10 + BUILD_NUMBER;
+   if (general_settings->get_int ("version") < schema_version) {
+     gm_application_show_assistant_window (app);
+     general_settings->set_int ("version", schema_version);
+   }
+ 
+   boost::shared_ptr<Ekiga::CallCore> call_core = app->priv->core->get<Ekiga::CallCore> ("call-core");
+   g_return_if_fail (call_core);
+   call_core->created_call.connect (boost::bind (&on_created_call_cb, _1, _2, (gpointer) app));
+ 
+   boost::shared_ptr<Ekiga::AccountCore> account_core = app->priv->core->get<Ekiga::AccountCore> 
("account-core");
+   g_return_if_fail (account_core);
+   account_core->questions.connect (boost::bind (&on_handle_questions_cb, _1, app));
+   account_core->account_added.connect (boost::bind (&on_account_modified_cb, _1, _2, app));
+   account_core->account_removed.connect (boost::bind (&on_account_modified_cb, _1, _2, app));
+ 
+   gm_application_populate_application_menu (app);
+ 
+   core->close ();
+   g_application_run (G_APPLICATION (app), argc, argv);
+ 
+   g_object_unref (app);
+ }
+ 
+ 
+ /* GObject stuff */
+ static void
+ gm_application_activate (GApplication *self)
+ {
+   GmApplication *app = GM_APPLICATION (self);
+ 
+   gm_application_show_main_window (app);
+ }
+ 
+ static void
+ gm_application_startup (GApplication *app)
+ {
+   GmApplication *self = GM_APPLICATION (app);
+   GMenuModel *app_menu = NULL;
+   gchar *path = NULL;
+ 
+   G_APPLICATION_CLASS (gm_application_parent_class)->startup (app);
+ 
+   /* Globals */
+ #if !GLIB_CHECK_VERSION(2,36,0)
+   g_type_init ();
+ #endif
+ #if !GLIB_CHECK_VERSION(2,32,0)
+   g_thread_init();
+ #endif
+ 
+ #ifndef WIN32
+   signal (SIGPIPE, SIG_IGN);
+ #endif
+ 
+   /* initialize platform-specific code */
+   gm_platform_init ();
+ #ifdef WIN32
+   // plugins (i.e. the audio/video ptlib/opal codecs) are searched in ./plugins
+   chdir (win32_datadir ());
+ #endif
+ 
+   /* Gettext initialization */
+   path = g_build_filename (DATA_DIR, "locale", NULL);
+   textdomain (GETTEXT_PACKAGE);
+   bindtextdomain (GETTEXT_PACKAGE, path);
+   bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+   g_free (path);
+ 
+   /* Application name */
+   g_set_application_name (_("Ekiga Softphone"));
+ #ifndef WIN32
+   setenv ("PULSE_PROP_application.name", _("Ekiga Softphone"), true);
+   setenv ("PA_PROP_MEDIA_ROLE", "phone", true);
+ #endif
+ 
+   /* Priv building */
+   self->priv = new _GmApplicationPrivate ();
+   self->priv->builder = gtk_builder_new ();
+ 
+   /* Menu */
+   g_action_map_add_action_entries (G_ACTION_MAP (self),
+                                    app_entries, G_N_ELEMENTS (app_entries),
+                                    self);
+   gtk_builder_add_from_string (self->priv->builder,
+                                "<?xml version=\"1.0\"?>"
+                                "<interface>"
+                                "  <menu id=\"appmenu\">"
+                                "    <section id=\"banks\">"
+                                "    </section>"
+                                "    <section>"
+                                "      <item>"
+                                "        <attribute name=\"label\" translatable=\"yes\">Address 
_Book</attribute>"
+                                "        <attribute name=\"action\">app.addressbook</attribute>"
+                                "      </item>"
+                                "    </section>"
+                                "    <section>"
+                                "      <item>"
+                                "        <attribute name=\"label\" 
translatable=\"yes\">_Preferences</attribute>"
+                                "        <attribute name=\"action\">app.preferences</attribute>"
+                                "      </item>"
+                                "    </section>"
+                                "    <section>"
+                                "      <item>"
+                                "        <attribute name=\"label\" translatable=\"yes\">_Help</attribute>"
+                                "        <attribute name=\"action\">app.help</attribute>"
+                                "        <attribute name=\"accel\">F1</attribute>"
+                                "      </item>"
+                                "      <item>"
+                                "        <attribute name=\"label\" translatable=\"yes\">_About</attribute>"
+                                "        <attribute name=\"action\">app.about</attribute>"
+                                "      </item>"
+                                "    </section>"
+                                "    <section>"
+                                "      <item>"
+                                "        <attribute name=\"label\" translatable=\"yes\">_Quit</attribute>"
+                                "        <attribute name=\"action\">app.quit</attribute>"
+                                "        <attribute name=\"accel\">&lt;Primary&gt;q</attribute>"
+                                "      </item>"
+                                "    </section>"
+                                "  </menu>"
+                                "</interface>", -1, NULL);
+ 
+   app_menu = G_MENU_MODEL (gtk_builder_get_object (self->priv->builder, "appmenu"));
+   gtk_application_set_app_menu (GTK_APPLICATION (self), app_menu);
+ 
+   self->priv->video_devices_settings =
+     boost::shared_ptr<Ekiga::Settings> (new Ekiga::Settings (VIDEO_DEVICES_SCHEMA));
+   g_signal_connect (self->priv->video_devices_settings->get_g_settings (),
+                     "changed::enable-preview",
+                     G_CALLBACK (video_preview_changed), self);
+   self->priv->call_window = NULL;
+ }
+ 
+ 
+ static void
+ gm_application_dispose (GObject *obj)
+ {
+   GmApplication *self = NULL;
+ 
+   self = GM_APPLICATION (obj);
+ 
+ #ifdef HAVE_DBUS
+   g_object_unref (self->priv->dbus_component);
+ #endif
+   g_object_unref (self->priv->builder);
+ 
+   delete self->priv;
+ 
+   G_OBJECT_CLASS (gm_application_parent_class)->dispose (obj);
+ }
+ 
+ 
+ static void
+ gm_application_shutdown (GApplication *app)
+ {
+   GmApplication *self = GM_APPLICATION (app);
+ 
+   g_return_if_fail (self);
+ 
+   PThread::Current()->Sleep (2000); // FIXME, This allows all threads to start and quit. Sucks.
+ 
+   gtk_widget_hide (GTK_WIDGET (self->priv->main_window));
+ 
+   self->priv->core.reset ();
+   Ekiga::Runtime::quit ();
+ 
+   gm_platform_shutdown ();
+ 
+   G_APPLICATION_CLASS (gm_application_parent_class)->shutdown (app);
+ }
+ 
+ static gint
+ gm_application_command_line (GApplication *app,
+                              GApplicationCommandLine *cl)
+ {
+   gchar **arguments = NULL;
+   GOptionContext *context = NULL;
+   GError *error = NULL;
+ 
+   GmApplication *self = GM_APPLICATION (app);
+ 
+   g_return_val_if_fail (self && self->priv->core, -1);
+ 
+   static gchar *url = NULL;
+   static int debug_level = 0;
+   static gboolean hangup = FALSE;
+   static gboolean help = FALSE;
+   static gboolean version = FALSE;
+ 
+   static GOptionEntry options [] =
+     {
+         {
+           "help", '?', 0, G_OPTION_ARG_NONE, &help,
+           N_("Show the application's help"), NULL
+         },
+ 
+         /* Version */
+         {
+           "version", 'V', 0, G_OPTION_ARG_NONE, &version,
+           N_("Show the application's version"), NULL
+         },
+         {
+           "debug", 'd', 0, G_OPTION_ARG_INT, &debug_level,
+           N_("Prints debug messages in the console (level between 1 and 8)"),
+           NULL
+         },
+         {
+           "call", 'c', 0, G_OPTION_ARG_STRING, &url,
+           N_("Makes Ekiga call the given URI"),
+           NULL
+         },
+         {
+           "hangup", '\0', 0, G_OPTION_ARG_NONE, &hangup,
+           N_("Hangup the current call (if any)"),
+           NULL
+         },
+         {
+           NULL, 0, 0, (GOptionArg)0, NULL,
+           NULL,
+           NULL
+         }
+     };
+ 
+   context = g_option_context_new (NULL);
+   g_option_context_add_main_entries (context, options, PACKAGE_NAME);
+   g_option_context_add_group (context, gtk_get_option_group (FALSE));
+ 
+   arguments = g_application_command_line_get_arguments (cl, NULL);
+ 
+   /* Avoid exit() on the main instance */
+   g_option_context_set_help_enabled (context, FALSE);
+ 
+   if (!option_context_parse (context, arguments, &error)) {
+     /* We should never get here since parsing would have
+      * failed on the client side... */
+     g_application_command_line_printerr (cl,
+                                          _("%s\nRun '%s --help' to see a full list of available command 
line options.\n"),
+                                          error->message, arguments[0]);
+ 
+     g_error_free (error);
+     g_application_command_line_set_exit_status (cl, 1);
+     g_application_quit (app);
+   }
+   else if (url) {
+     boost::shared_ptr<Ekiga::CallCore> call_core =
+       self->priv->core->get<Ekiga::CallCore> ("call-core");
+     call_core->dial (url);
+   }
+   else if (hangup) {
+     boost::shared_ptr<Ekiga::CallCore> call_core =
+       self->priv->core->get<Ekiga::CallCore> ("call-core");
+     call_core->hang_up ();
+   }
+   else if (version) {
+     g_print ("%s - Version %d.%d.%d\n",
+              g_get_application_name (),
+              MAJOR_VERSION, MINOR_VERSION, BUILD_NUMBER);
+     g_application_quit (app);
+   }
+   else if (help) {
+     g_print (g_option_context_get_help (context, TRUE, NULL));
+     g_application_quit (app);
+   }
+   else if (debug_level > 0) {
+ #ifndef WIN32
+     char* text_label =  g_strdup_printf ("%d", debug_level);
+     setenv ("PTLIB_TRACE_CODECS", text_label, TRUE);
+     g_free (text_label);
+ #else
+     char* text_label =  g_strdup_printf ("PTLIB_TRACE_CODECS=%d", debug_level);
+     _putenv (text_label);
+     g_free (text_label);
+     if (debug_level != 0) {
+       std::string desk_path = g_get_user_special_dir (G_USER_DIRECTORY_DESKTOP);
+       if (!desk_path.empty ())
+         std::freopen((desk_path + "\\ekiga-stderr.txt").c_str (), "w", stderr);
+     }
+ #endif
+ 
+ #if PTRACING
+     PTrace::Initialise (PMAX (PMIN (8, debug_level), 0), NULL,
+                         PTrace::Timestamp | PTrace::Thread
+                         | PTrace::Blocks | PTrace::DateAndTime);
+     PTRACE (1, "Ekiga version "
+             << MAJOR_VERSION << "." << MINOR_VERSION << "." << BUILD_NUMBER);
+ #ifdef EKIGA_REVISION
+     PTRACE (1, "Ekiga git revision: " << EKIGA_REVISION);
+ #endif
+     PTRACE (1, "PTLIB version " << PTLIB_VERSION);
+     PTRACE (1, "OPAL version " << OPAL_VERSION);
+ #ifdef HAVE_DBUS
+     PTRACE (1, "DBUS support enabled");
+ #else
+     PTRACE (1, "DBUS support disabled");
+ #endif
+ #endif
+   }
+ 
+   g_strfreev (arguments);
+   g_option_context_free (context);
+ 
+   g_application_activate (app);
+ 
+   g_free (url);
+   url = NULL;
+   hangup = FALSE;
+   version = FALSE;
+   help = FALSE;
+ 
+   return 0;
+ }
+ 
+ static void
+ gm_application_class_init (GmApplicationClass *klass)
+ {
+   GObjectClass *object_class = G_OBJECT_CLASS (klass);
+   GApplicationClass *app_class = G_APPLICATION_CLASS (klass);
+ 
+   object_class->dispose = gm_application_dispose;
+ 
+   app_class->startup = gm_application_startup;
+   app_class->activate = gm_application_activate;
+   app_class->command_line = gm_application_command_line;
+   app_class->shutdown = gm_application_shutdown;
+ }
+ 
+ 
+ static void
+ gm_application_init (G_GNUC_UNUSED GmApplication *self)
+ {
+   self->priv = new GmApplicationPrivate ();
+   self->priv->banks_actions_count = 0;
+ }
+ 
+ 
+ GmApplication *
+ gm_application_new ()
+ {
+   GmApplication *self =
+     GM_APPLICATION (g_object_new (GM_TYPE_APPLICATION,
+                                   "application-id", "org.gnome.Ekiga",
+                                   "flags", G_APPLICATION_HANDLES_COMMAND_LINE,
+                                   NULL));
+   g_application_register (G_APPLICATION (self), NULL, NULL);
+ 
+   return self;
+ }
+ 
+ 
+ void
+ gm_application_set_core (GmApplication *self,
+                          Ekiga::ServiceCorePtr core)
+ {
+   g_return_if_fail (GM_IS_APPLICATION (self));
+   self->priv->core = core;
+ }
+ 
+ 
+ Ekiga::ServiceCorePtr
+ gm_application_get_core (GmApplication *self)
+ {
+   g_return_val_if_fail (GM_IS_APPLICATION (self), boost::shared_ptr<Ekiga::ServiceCore> ());
+ 
+   return self->priv->core;
+ }
+ 
+ 
+ void
+ gm_application_show_main_window (GmApplication *self)
+ {
+   g_return_if_fail (GM_IS_APPLICATION (self));
+ 
+   gtk_window_present (GTK_WINDOW (self->priv->main_window));
+ }
+ 
+ 
+ void
+ gm_application_hide_main_window (GmApplication *self)
+ {
+   g_return_if_fail (GM_IS_APPLICATION (self));
+ 
+   gtk_widget_hide (self->priv->main_window);
+ }
+ 
+ 
+ GtkWidget *
+ gm_application_get_main_window (GmApplication *self)
+ {
+   g_return_val_if_fail (GM_IS_APPLICATION (self), NULL);
+ 
+   return self->priv->main_window;
+ }
+ 
+ 
+ gboolean
+ gm_application_show_help (GmApplication *app,
+                           G_GNUC_UNUSED const gchar *link_id)
+ {
+   g_return_val_if_fail (GM_IS_APPLICATION (app), FALSE);
+ 
+   GtkWindow *parent = gtk_application_get_active_window (GTK_APPLICATION (app));
+ 
+ #ifdef WIN32
+   gchar *locale, *loc_ , *index_path;
+   int hinst = 0;
+ 
+   locale = g_win32_getlocale ();
+   if (strlen (locale) > 0) {
+ 
+     /* try returned locale first, it may be fully qualified e.g. zh_CN */
+     index_path = g_build_filename (WIN32_HELP_DIR, locale,
+                                  WIN32_HELP_FILE, NULL);
+     hinst = (int) ShellExecute (NULL, "open", index_path, NULL,
+                               DATA_DIR, SW_SHOWNORMAL);
+     g_free (index_path);
+   }
+ 
+   if (hinst <= 32 && (loc_ = g_strrstr (locale, "_"))) {
+     /* on error, try short locale */
+     *loc_ = 0;
+     index_path = g_build_filename (WIN32_HELP_DIR, locale,
+                                  WIN32_HELP_FILE, NULL);
+     hinst = (int) ShellExecute (NULL, "open", index_path, NULL,
+                               DATA_DIR, SW_SHOWNORMAL);
+     g_free (index_path);
+   }
+ 
+   g_free (locale);
+ 
+   if (hinst <= 32) {
+ 
+     /* on error or missing locale, try default locale */
+     index_path = g_build_filename (WIN32_HELP_DIR, "C", WIN32_HELP_FILE, NULL);
+     (void)ShellExecute (NULL, "open", index_path, NULL,
+                       DATA_DIR, SW_SHOWNORMAL);
+     g_free (index_path);
+   }
+ #else /* !WIN32 */
+   GError *err = NULL;
+   gboolean success = FALSE;
+ 
+   success = gtk_show_uri (NULL, "ghelp:" PACKAGE_NAME, GDK_CURRENT_TIME, &err);
+ 
+   if (!success) {
+     GtkWidget *d;
+     d = gtk_message_dialog_new (NULL,
+                                 (GtkDialogFlags) (GTK_DIALOG_MODAL),
+                                 GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
+                                 "%s", _("Unable to open help file."));
+     gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (d),
+                                               "%s", err->message);
+     g_signal_connect (d, "response", G_CALLBACK (gtk_widget_destroy), NULL);
+     gtk_window_set_transient_for (GTK_WINDOW (d), GTK_WINDOW (parent));
+     gtk_window_present (GTK_WINDOW (d));
+     g_error_free (err);
+     return FALSE;
+   }
+ #endif
+ 
+   return TRUE;
+ }
+ 
+ 
+ void
+ gm_application_show_about (GmApplication *app)
+ {
+   g_return_if_fail (GM_IS_APPLICATION (app));
+ 
+   GtkWidget *pixmap = NULL;
+   gchar *filename = NULL;
+ 
+   const gchar *authors [] = {
+       "Damien Sandras <dsandras seconix com>",
+       "",
+       N_("Contributors:"),
+       "Eugen Dedu <eugen dedu pu-pm univ-fcomte fr>",
+       "Julien Puydt <julien puydt laposte net>",
+       "Robert Jongbloed <rjongbloed postincrement com>",
+       "",
+       N_("Artwork:"),
+       "Fabian Deutsch <fabian deutsch gmx de>",
+       "Vinicius Depizzol <vdepizzol gmail com>",
+       "Andreas Kwiatkowski <post kwiat org>",
+       "Carlos Pardo <me m4de com>",
+       "Jakub Steiner <jimmac ximian com>",
+       "",
+       N_("See AUTHORS file for full credits"),
+       NULL
+   };
+ 
+   authors [2] = gettext (authors [2]);
+   authors [7] = gettext (authors [7]);
+   authors [14] = gettext (authors [14]);
+ 
+   const gchar *documenters [] = {
+     "Damien Sandras <dsandras seconix com>",
+     "Christopher Warner <zanee kernelcode com>",
+     "Matthias Redlich <m-redlich t-online de>",
+     NULL
+   };
+ 
+   const gchar *license[] = {
+ N_("This program is free software; you can redistribute it and/or modify \
+ it under the terms of the GNU General Public License as published by \
+ the Free Software Foundation; either version 2 of the License, or \
+ (at your option) any later version. "),
+ N_("This program is distributed in the hope that it will be useful, \
+ but WITHOUT ANY WARRANTY; without even the implied warranty of \
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the \
+ GNU General Public License for more details. \
+ You should have received a copy of the GNU General Public License \
+ along with this program; if not, write to the Free Software Foundation, \
+ Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA."),
+ N_("Ekiga is licensed under the GPL license and as a special exception, \
+ you have permission to link or otherwise combine this program with the \
+ programs OPAL, OpenH323 and PWLIB, and distribute the combination, \
+ without applying the requirements of the GNU GPL to the OPAL, OpenH323 \
+ and PWLIB programs, as long as you do follow the requirements of the \
+ GNU GPL for all the rest of the software thus combined.")
+   };
+ 
+   gchar *license_trans;
+ 
+   /* Translators: Please write translator credits here, and
+    * separate names with \n */
+   const gchar *translator_credits = _("translator-credits");
+   if (g_strcmp0 (translator_credits, "translator-credits") == 0)
+     translator_credits = "No translators, English by\n"
+         "Damien Sandras <dsandras seconix com>";
+ 
+   const gchar *comments =  _("Ekiga is full-featured SIP and H.323 compatible VoIP, IP-Telephony and 
Videoconferencing application that allows you to make audio and video calls to remote users with SIP and 
H.323 hardware or software.");
+ 
+   license_trans = g_strconcat (_(license[0]), "\n\n", _(license[1]), "\n\n",
+                                _(license[2]), "\n\n", NULL);
+ 
+   filename = g_build_filename (DATA_DIR, "pixmaps", PACKAGE_NAME,
+                                PACKAGE_NAME "-logo.png", NULL);
+   pixmap =  gtk_image_new_from_file (filename);
+ 
+   gtk_show_about_dialog (GTK_WINDOW (gtk_application_get_active_window (GTK_APPLICATION (app))),
+                          "name", "Ekiga",
+                          "version", VERSION,
+                          "copyright", "Copyright © 2000-2014 Damien Sandras",
+                          "authors", authors,
+                          "documenters", documenters,
+                          "translator-credits", translator_credits,
+                          "comments", comments,
+                          "logo", gtk_image_get_pixbuf (GTK_IMAGE (pixmap)),
+                          "license", license_trans,
+                          "wrap-license", TRUE,
+                          "website", "http://www.ekiga.org";,
+                          NULL);
+ 
+   g_free (license_trans);
+   g_free (filename);
+ }
+ 
+ 
+ void
+ gm_application_show_chat_window (GmApplication *self)
+ {
+   g_return_if_fail (GM_IS_APPLICATION (self));
+ 
+   // FIXME: We should move the chat window to a build & destroy scheme
+   // but unread-alert prevents this
+   gtk_window_present (GTK_WINDOW (self->priv->chat_window));
+ }
+ 
+ 
+ GtkWidget *
+ gm_application_get_chat_window (GmApplication *self)
+ {
+   g_return_val_if_fail (GM_IS_APPLICATION (self), NULL);
+ 
+   return self->priv->chat_window;
+ }
+ 
+ 
+ void
+ gm_application_show_preferences_window (GmApplication *self)
+ {
+   GtkWindow *parent = NULL;
+   GtkWindow *window = NULL;
+ 
+   g_return_if_fail (GM_IS_APPLICATION (self));
+ 
+   parent = gtk_application_get_active_window (GTK_APPLICATION (self));
+ 
+   window = GTK_WINDOW (preferences_window_new (self));
+   gtk_window_set_transient_for (GTK_WINDOW (window), GTK_WINDOW (parent));
+   gtk_window_present (window);
+ }
+ 
+ 
+ void
+ gm_application_show_addressbook_window (GmApplication *self)
+ {
+   g_return_if_fail (GM_IS_APPLICATION (self));
+ 
+ 
+   gtk_window_present (GTK_WINDOW (addressbook_window_new (self)));
+ }
+ 
+ 
+ void
+ gm_application_show_assistant_window (GmApplication *self)
+ {
+   GtkWindow *parent = NULL;
+   GtkWindow *window = NULL;
+ 
+   g_return_if_fail (GM_IS_APPLICATION (self));
+ 
+   parent = gtk_application_get_active_window (GTK_APPLICATION (self));
+ 
+   window = GTK_WINDOW (assistant_window_new (self));
+   gtk_window_set_transient_for (GTK_WINDOW (window), GTK_WINDOW (parent));
+   gtk_window_present (window);
+ }
diff --cc lib/engine/gui/gtk-frontend/main_window.cpp
index 2b4b01e,9d6813e..162a47c
--- a/lib/engine/gui/gtk-frontend/main_window.cpp
+++ b/lib/engine/gui/gtk-frontend/main_window.cpp
@@@ -626,18 -416,13 +417,13 @@@ static void on_cleared_call_cb (boost::
      mw->priv->current_call = boost::shared_ptr<Ekiga::Call>();
    mw->priv->calling_state = Standby;
  
-   /* Info message */
-   ekiga_main_window_flash_message (mw, "%s", reason.c_str ());
  
    /* Sound events */
 -  mw->priv->audiooutput_core->stop_play_event("incoming_call_sound");
 -  mw->priv->audiooutput_core->stop_play_event("ring_tone_sound");
 +  mw->priv->audiooutput_core->stop_play_event("incoming-call-sound");
 +  mw->priv->audiooutput_core->stop_play_event("ring-tone-sound");
  
-   /* Hide call window */
-   g_timeout_add_seconds (2, on_delayed_hide_call_window_cb, mw);
- 
    /* Sensitive a few things back */
-   gtk_widget_set_sensitive (GTK_WIDGET (mw->priv->uri_toolbar), true);
+   gtk_widget_set_sensitive (GTK_WIDGET (mw->priv->entry), true);
    gtk_widget_set_sensitive (GTK_WIDGET (mw->priv->preview_button), true);
  }
  
@@@ -1049,83 -620,43 +621,44 @@@ ekiga_main_window_init_actions_toolbar 
  
    g_return_if_fail (EKIGA_IS_MAIN_WINDOW (mw));
  
-   /* The call horizontal toolbar */
-   mw->priv->actions_toolbar = gtk_toolbar_new ();
-   gtk_toolbar_set_style (GTK_TOOLBAR (mw->priv->actions_toolbar), GTK_TOOLBAR_ICONS);
-   gtk_toolbar_set_show_arrow (GTK_TOOLBAR (mw->priv->actions_toolbar), FALSE);
- 
-   /* The video preview button */
-   image = gtk_image_new_from_icon_name ("camera-web", GTK_ICON_SIZE_MENU);
-   mw->priv->preview_button = GTK_WIDGET (gtk_toggle_tool_button_new ());
-   gtk_tool_button_set_icon_widget (GTK_TOOL_BUTTON (mw->priv->preview_button), image);
-   gtk_tool_item_set_expand (GTK_TOOL_ITEM (mw->priv->preview_button), false);
-   gtk_toolbar_insert (GTK_TOOLBAR (mw->priv->actions_toolbar), GTK_TOOL_ITEM (mw->priv->preview_button), 
-1);
+   mw->priv->actions_toolbar = gtk_header_bar_new ();
+   gtk_window_set_titlebar (GTK_WINDOW (mw), mw->priv->actions_toolbar);
+ 
+   /* Start packing buttons */
+   button = gtk_button_new ();
+   image = gtk_image_new_from_icon_name ("call-start-symbolic", GTK_ICON_SIZE_MENU);
+   gtk_button_set_image (GTK_BUTTON (button), image);
+   gtk_widget_set_tooltip_text (GTK_WIDGET (button),
+                                _("Call the selected contact"));
+   gtk_actionable_set_detailed_action_name (GTK_ACTIONABLE (button), "win.call");
+   gtk_header_bar_pack_start (GTK_HEADER_BAR (mw->priv->actions_toolbar), button);
+ 
+   mw->priv->preview_button = gtk_toggle_button_new ();
+   image = gtk_image_new_from_icon_name ("camera-web-symbolic", GTK_ICON_SIZE_MENU);
+   gtk_button_set_image (GTK_BUTTON (mw->priv->preview_button), image);
    gtk_widget_set_tooltip_text (GTK_WIDGET (mw->priv->preview_button),
                                 _("Display images from your camera device"));
-   g_settings_bind (mw->priv->video_devices_settings->get_g_settings (),
-                    "enable-preview",
-                    mw->priv->preview_button,
-                    "active",
-                    G_SETTINGS_BIND_DEFAULT);
-   g_signal_connect (mw->priv->preview_button, "toggled",
-                     G_CALLBACK (video_preview_changed), mw);
- 
-   /* Separator */
-   item = gtk_separator_tool_item_new ();
-   gtk_toolbar_insert (GTK_TOOLBAR (mw->priv->actions_toolbar),
-                     GTK_TOOL_ITEM (item), -1);
- 
-   /* The roster button */
-   image = gtk_image_new_from_icon_name ("avatar-default", GTK_ICON_SIZE_MENU);
-   mw->priv->toggle_buttons[CONTACTS] = gtk_radio_tool_button_new (NULL);
-   gtk_tool_button_set_icon_widget (GTK_TOOL_BUTTON (mw->priv->toggle_buttons[CONTACTS]), image);
-   gtk_tool_item_set_expand (GTK_TOOL_ITEM (mw->priv->toggle_buttons[CONTACTS]), false);
-   gtk_toolbar_insert (GTK_TOOLBAR (mw->priv->actions_toolbar), mw->priv->toggle_buttons[CONTACTS], -1);
-   gtk_widget_set_tooltip_text (GTK_WIDGET (mw->priv->toggle_buttons[CONTACTS]),
-                                _("View the contacts list"));
-   g_settings_bind_with_mapping (mw->priv->user_interface_settings->get_g_settings (),
-                                 "panel-section", mw->priv->toggle_buttons[CONTACTS],
-                                 "active",
-                                 G_SETTINGS_BIND_DEFAULT,
-                                 string_gsettings_get_from_active, string_gsettings_set_from_active,
-                                 (gpointer) "contacts",
-                                 NULL);
- 
-   /* The dialpad button */
-   image = gtk_image_new_from_icon_name ("input-dialpad", GTK_ICON_SIZE_MENU);
-   mw->priv->toggle_buttons[DIALPAD] =
-     gtk_radio_tool_button_new (gtk_radio_tool_button_get_group (GTK_RADIO_TOOL_BUTTON 
(mw->priv->toggle_buttons[CONTACTS])));
-   gtk_tool_button_set_icon_widget (GTK_TOOL_BUTTON (mw->priv->toggle_buttons[DIALPAD]), image);
-   gtk_tool_item_set_expand (GTK_TOOL_ITEM (mw->priv->toggle_buttons[DIALPAD]), false);
-   gtk_toolbar_insert (GTK_TOOLBAR (mw->priv->actions_toolbar), mw->priv->toggle_buttons[DIALPAD], -1);
-   gtk_widget_set_tooltip_text (GTK_WIDGET (mw->priv->toggle_buttons[DIALPAD]),
-                                _("View the dialpad"));
-   g_settings_bind_with_mapping (mw->priv->user_interface_settings->get_g_settings (),
-                                 "panel-section", mw->priv->toggle_buttons[DIALPAD],
-                                 "active",
-                                 G_SETTINGS_BIND_DEFAULT,
-                                 string_gsettings_get_from_active, string_gsettings_set_from_active,
-                                 (gpointer) "dialpad",
-                                 NULL);
- 
-   /* The history button */
-   image = gtk_image_new_from_icon_name ("document-open-recent", GTK_ICON_SIZE_MENU);
-   mw->priv->toggle_buttons[CALL] =
-     gtk_radio_tool_button_new (gtk_radio_tool_button_get_group (GTK_RADIO_TOOL_BUTTON 
(mw->priv->toggle_buttons[CONTACTS])));
-   gtk_tool_button_set_icon_widget (GTK_TOOL_BUTTON (mw->priv->toggle_buttons[CALL]), image);
-   gtk_tool_item_set_expand (GTK_TOOL_ITEM (mw->priv->toggle_buttons[CALL]), false);
-   gtk_toolbar_insert (GTK_TOOLBAR (mw->priv->actions_toolbar), mw->priv->toggle_buttons[CALL], -1);
-   gtk_widget_set_tooltip_text (GTK_WIDGET (mw->priv->toggle_buttons[CALL]),
-                                _("View the call history"));
-   g_settings_bind_with_mapping (mw->priv->user_interface_settings->get_g_settings (),
-                                 "panel-section", mw->priv->toggle_buttons[CALL],
-                                 "active",
-                                 G_SETTINGS_BIND_DEFAULT,
-                                 string_gsettings_get_from_active, string_gsettings_set_from_active,
-                                 (gpointer) "call-history",
-                                 NULL);
++
+   gtk_actionable_set_detailed_action_name (GTK_ACTIONABLE (mw->priv->preview_button),
+                                            "win.enable-preview");
+   gtk_header_bar_pack_start (GTK_HEADER_BAR (mw->priv->actions_toolbar), mw->priv->preview_button);
+ 
+   switcher = gtk_stack_switcher_new ();
+   gtk_stack_switcher_set_stack (GTK_STACK_SWITCHER (switcher), GTK_STACK (mw->priv->main_stack));
+   gtk_header_bar_set_custom_title (GTK_HEADER_BAR (mw->priv->actions_toolbar), switcher);
+   gtk_widget_set_margin_end (GTK_WIDGET (switcher), 6);
+ 
+   mw->priv->menu_button = gtk_menu_button_new ();
+   g_object_set (G_OBJECT (mw->priv->menu_button), "use-popover", true, NULL);
+   image = gtk_image_new_from_icon_name ("open-menu-symbolic", GTK_ICON_SIZE_MENU);
+   gtk_button_set_image (GTK_BUTTON (mw->priv->menu_button), image);
+   gtk_header_bar_pack_end (GTK_HEADER_BAR (mw->priv->actions_toolbar), mw->priv->menu_button);
+   gtk_widget_show_all (mw->priv->actions_toolbar);
+ 
+   gtk_header_bar_set_show_close_button (GTK_HEADER_BAR (mw->priv->actions_toolbar), TRUE);
  }
  
+ 
  static void
  ekiga_main_window_init_menu (EkigaMainWindow *mw)
  {
diff --cc lib/engine/gui/gtk-frontend/preferences-window.cpp
index e82fde3,17be036..6d1fb08
--- a/lib/engine/gui/gtk-frontend/preferences-window.cpp
+++ b/lib/engine/gui/gtk-frontend/preferences-window.cpp
@@@ -48,11 -48,13 +48,15 @@@
  #include "default_devices.h"
  
  #include "scoped-connections.h"
 +#include "form-request-simple.h"
 +#include "form-dialog-gtk.h"
  
- #include "gmcallbacks.h"
  #include "codecsbox.h"
+ #include "gm-entry.h"
+ 
+ #ifndef HAVE_SIDEBAR
+ #include "gm-sidebar.h"
+ #endif
  
  #ifdef WIN32
  #include "platform/winpaths.h"
@@@ -451,21 -447,6 +449,25 @@@ static void sound_event_setting_change
                                           gpointer data);
  
  
 +/* DESCRIPTION : This callback is triggered when the user asks to edit
 + *               the blacklist
 + * BEHAVIOR    : Display a form to edit the blacklist
 + * PRE         : A pointer to the preferences window
 + */
 +static void edit_blacklist_cb (GtkWidget* widget,
 +                             gpointer data);
 +
- /* DESCRIPTION : This callback is triggered when the user submits the blacklist-editing form
++
++/* DESCRIPTION : This callback is triggered when the user submits the
++ *               blacklist-editing form
 + * BEHAVIOR    : /
 + * PRE         : A pointer to the preferences window
 + */
- static void on_edit_blacklist_form_submitted (bool submitted,
-                                             Ekiga::Form& result);
++static bool on_edit_blacklist_form_submitted (bool submitted,
++                                            Ekiga::Form& result,
++                                              std::string& error);
++
 +
  /* Implementation */
  static void
  gm_prefs_window_sound_events_list_build (PreferencesWindow *self)
@@@ -1668,43 -1619,6 +1653,44 @@@ sound_event_toggled_cb (G_GNUC_UNUSED G
    gtk_tree_path_free (path);
  }
  
 +static void
 +edit_blacklist_cb (GtkWidget* /*widget*/,
 +                 gpointer data)
 +{
 +  g_return_if_fail (data != NULL);
 +
-   boost::shared_ptr<Ekiga::FormRequestSimple> request(new Ekiga::FormRequestSimple 
(&on_edit_blacklist_form_submitted));
++  boost::shared_ptr<Ekiga::FormRequestSimple> request (new Ekiga::FormRequestSimple 
(&on_edit_blacklist_form_submitted));
 +
-   request->title (_("Blacklist edition"));
-   request->instructions (_("This form lets you add and remove tokens from the blacklist"));
++  request->title (_("Edit the Blacklist"));
 +
 +  boost::scoped_ptr<Ekiga::Settings> settings(new Ekiga::Settings (CONTACTS_SCHEMA));
 +  std::list<std::string> foes(settings->get_string_list ("foe-list"));
 +
-   request->editable_set ("foes", _("Current list of undesirables"),
-                        std::set<std::string> (foes.begin (), foes.end ()),
-                        std::set<std::string>());
++  request->editable_list ("foes", _("Current list of undesirables"),
++                       std::list<std::string> (foes.begin (), foes.end ()),
++                       std::list<std::string>());
 +
 +  FormDialog dialog(request, GTK_WIDGET (data));
 +
 +  dialog.run ();
 +}
 +
- static void
++static bool
 +on_edit_blacklist_form_submitted (bool submitted,
-                                 Ekiga::Form& result)
++                                Ekiga::Form& result,
++                                  G_GNUC_UNUSED std::string& error)
 +{
 +  if (!submitted)
-     return;
++    return false;
 +
-   std::set<std::string> foes = result.editable_set ("foes");
++  std::list<std::string> foes = result.editable_list ("foes");
 +  boost::scoped_ptr<Ekiga::Settings> settings(new Ekiga::Settings (CONTACTS_SCHEMA));
-   settings->set_string_list ("foe-list",
-                            std::list<std::string> (foes.begin (), foes.end ()));
++  settings->set_string_list ("foe-list", foes);
++
++  return true;
 +}
 +
 +
  void on_videoinput_device_added_cb (const Ekiga::VideoInputDevice & device,
                                      PreferencesWindow *self)
  {
diff --cc lib/engine/presence/presence-core.h
index 718f933,cb299d4..0978766
--- a/lib/engine/presence/presence-core.h
+++ b/lib/engine/presence/presence-core.h
@@@ -41,7 -41,9 +41,8 @@@
  #include "services.h"
  #include "scoped-connections.h"
  #include "cluster.h"
 -#include "account-core.h"
  #include "personal-details.h"
+ #include "action-provider.h"
  
  namespace Ekiga
  {
diff --cc lib/engine/presence/uri-presentity.cpp
index 12f874e,7b14947..60e320e
--- a/lib/engine/presence/uri-presentity.cpp
+++ b/lib/engine/presence/uri-presentity.cpp
@@@ -48,17 -48,11 +48,17 @@@ struct null_delete
  Ekiga::URIPresentity::URIPresentity (boost::shared_ptr<Ekiga::PresenceCore> pcore,
                                     std::string name_,
                                     std::string uri_,
-                                    std::set<std::string> groups_):
+                                    std::list<std::string> groups_):
    presence_core(pcore), name(name_), uri(uri_), presence("unknown"), groups(groups_)
  {
 -  pcore->presence_received.connect (boost::bind (&Ekiga::URIPresentity::on_presence_received, this, _1, 
_2));
 -  pcore->status_received.connect (boost::bind (&Ekiga::URIPresentity::on_status_received, this, _1, _2));
 +  boost::signals2::connection conn;
 +
 +  conn = pcore->presence_received.connect (boost::bind (&Ekiga::URIPresentity::on_presence_received, this, 
_1, _2));
 +  connections.add (conn);
 +
 +  conn = pcore->status_received.connect (boost::bind (&Ekiga::URIPresentity::on_status_received, this, _1, 
_2));
 +  connections.add (conn);
 +
    pcore->fetch_presence (uri);
  }
  
diff --cc lib/engine/presence/uri-presentity.h
index 1076bc7,dc1c12a..466a7ec
--- a/lib/engine/presence/uri-presentity.h
+++ b/lib/engine/presence/uri-presentity.h
@@@ -90,15 -90,8 +90,9 @@@ namespace Ekig
  
      const std::string get_uri () const;
  
-     /** Populates the given Ekiga::MenuBuilder with the actions.
-      * @param: A MenuBuilder.
-      */
-     bool populate_menu (Ekiga::MenuBuilder& builder);
- 
    private:
- 
      boost::weak_ptr<Ekiga::PresenceCore> presence_core;
 +    Ekiga::scoped_connections connections;
  
      std::string name;
      std::string uri;
diff --cc lib/engine/protocol/call-core.cpp
index 4002251,6f42846..81bfdea
--- a/lib/engine/protocol/call-core.cpp
+++ b/lib/engine/protocol/call-core.cpp
@@@ -40,8 -45,7 +45,7 @@@
  
  using namespace Ekiga;
  
- CallCore::CallCore (boost::shared_ptr<Ekiga::FriendOrFoe> iff_):
-   iff(iff_)
 -CallCore::CallCore ()
++CallCore::CallCore (boost::shared_ptr<Ekiga::FriendOrFoe> iff_): iff(iff_)
  {
    nr_ready = 0;
  }
@@@ -92,31 -97,84 +97,92 @@@ bool CallCore::dial (const std::string 
  }
  
  
- void
- CallCore::add_call (boost::shared_ptr<Call> call,
-                   boost::shared_ptr<CallManager> manager)
+ void CallCore::hang_up ()
+ {
+   for (std::set<boost::shared_ptr<CallManager> >::iterator iter = managers.begin ();
+        iter != managers.end ();
+        iter++)
+     (*iter)->hang_up ();
+ }
+ 
+ 
+ bool CallCore::transfer (const std::string & uri,
+                          bool attended)
+ {
+   for (std::set<boost::shared_ptr<CallManager> >::iterator iter = managers.begin ();
+        iter != managers.end ();
+        iter++) {
+     if ((*iter)->transfer (uri, attended))
+       return true;
+   }
+ 
+   return false;
+ }
+ 
+ 
+ bool CallCore::message (const ContactPtr & contact,
+                         const std::string & uri)
+ {
+   for (std::set<boost::shared_ptr<CallManager> >::iterator iter = managers.begin ();
+        iter != managers.end ();
+        iter++) {
+     if ((*iter)->message (contact, uri))
+       return true;
+   }
+ 
+   return false;
+ }
+ 
+ 
+ bool CallCore::is_supported_uri (const std::string & uri)
+ {
+   for (std::set<boost::shared_ptr<CallManager> >::iterator iter = managers.begin ();
+        iter != managers.end ();
+        iter++) {
+     if ((*iter)->is_supported_uri (uri))
+       return true;
+   }
+ 
+   return false;
+ }
+ 
+ 
+ void CallCore::add_call (boost::shared_ptr<Call> call, boost::shared_ptr<CallManager> manager)
  {
 +  Ekiga::FriendOrFoe::Identification id = iff->decide ("call", call->get_remote_uri ());
 +
 +  if (id == Ekiga::FriendOrFoe::Foe) {
 +
 +    call->hang_up ();
 +    return;
 +  }
 +
+   created_call (manager, call);
+ 
    boost::shared_ptr<Ekiga::scoped_connections> conns(new Ekiga::scoped_connections);
  
-   conns->add (call->ringing.connect (boost::bind (&CallCore::on_ringing_call, this, call, manager)));
-   conns->add (call->setup.connect (boost::bind (&CallCore::on_setup_call, this, call, manager)));
-   conns->add (call->missed.connect (boost::bind (&CallCore::on_missed_call, this, call, manager)));
-   conns->add (call->cleared.connect (boost::bind (&CallCore::on_cleared_call, this, _1, call, manager)));
-   conns->add (call->established.connect (boost::bind (&CallCore::on_established_call, this, call, 
manager)));
-   conns->add (call->held.connect (boost::bind (&CallCore::on_held_call, this, call, manager)));
-   conns->add (call->retrieved.connect (boost::bind (&CallCore::on_retrieved_call, this, call, manager)));
-   conns->add (call->stream_opened.connect (boost::bind (&CallCore::on_stream_opened, this, _1, _2, _3, 
call, manager)));
-   conns->add (call->stream_closed.connect (boost::bind (&CallCore::on_stream_closed, this, _1, _2, _3, 
call, manager)));
-   conns->add (call->stream_paused.connect (boost::bind (&CallCore::on_stream_paused, this, _1, _2, call, 
manager)));
-   conns->add (call->stream_resumed.connect (boost::bind (&CallCore::on_stream_resumed, this, _1, _2, call, 
manager)));
+   conns->add (call->ringing.connect (boost::bind (&CallCore::on_ringing_call, this,
+                                                   call, manager)));
+   conns->add (call->setup.connect (boost::bind (&CallCore::on_setup_call, this,
+                                                 call, manager)));
+   conns->add (call->missed.connect (boost::bind (&CallCore::on_missed_call, this,
+                                                  call, manager)));
+   conns->add (call->cleared.connect (boost::bind (&CallCore::on_cleared_call, this,
+                                                   _1, call, manager)));
+   conns->add (call->established.connect (boost::bind (&CallCore::on_established_call, this,
+                                                       call, manager)));
+   conns->add (call->held.connect (boost::bind (&CallCore::on_held_call, this,
+                                                call, manager)));
+   conns->add (call->retrieved.connect (boost::bind (&CallCore::on_retrieved_call, this,
+                                                     call, manager)));
+   conns->add (call->stream_opened.connect (boost::bind (&CallCore::on_stream_opened, this,
+                                                         _1, _2, _3, call, manager)));
+   conns->add (call->stream_closed.connect (boost::bind (&CallCore::on_stream_closed, this,
+                                                         _1, _2, _3, call, manager)));
+   conns->add (call->stream_paused.connect (boost::bind (&CallCore::on_stream_paused, this,
+                                                         _1, _2, call, manager)));
+   conns->add (call->stream_resumed.connect (boost::bind (&CallCore::on_stream_resumed, this,
+                                                          _1, _2, call, manager)));
    conns->add (call->removed.connect (boost::bind (&CallCore::on_call_removed, this, call)));
  
    call_connections [call->get_id ()] = conns;
diff --cc plugins/avahi/Makefile.am
index 82bcd51,f57626d..1cd9cb8
--- a/plugins/avahi/Makefile.am
+++ b/plugins/avahi/Makefile.am
@@@ -2,7 -2,7 +2,8 @@@ plugin_LTLIBRARIES = libgmavahi.l
  
  AM_CXXFLAGS = \
        $(BOOST_CPPFLAGS) $(AVAHI_CFLAGS) \
 +      -I$(top_srcdir)/lib/engine \
+       -I$(top_srcdir)/lib/engine/action \
        -I$(top_srcdir)/lib/engine/framework \
        -I$(top_srcdir)/lib/engine/account \
        -I$(top_srcdir)/lib/engine/presence \
diff --cc plugins/libnotify/Makefile.am
index b7ca344,69996d5..72e8fdc
--- a/plugins/libnotify/Makefile.am
+++ b/plugins/libnotify/Makefile.am
@@@ -2,9 -2,10 +2,11 @@@ plugin_LTLIBRARIES = libgmlibnotify.l
  
  AM_CXXFLAGS = \
        $(BOOST_CPPFLAGS) $(NOTIFY_CFLAGS) \
 +      -I$(top_srcdir)/lib/engine \
        -I$(top_srcdir)/lib/engine/framework \
        -I$(top_srcdir)/lib/engine/notification \
+       -I$(top_srcdir)/lib/engine/action       \
+       -I$(top_srcdir)/lib/engine/addressbook \
        -I$(top_srcdir)/lib/engine/protocol
  
  libgmlibnotify_la_SOURCES = \


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]