]> git.0d.be Git - empathy.git/blob - src/empathy.c
Initialize telepathy-yell
[empathy.git] / src / empathy.c
1 /*
2  * Copyright (C) 2007-2009 Collabora Ltd.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public
15  * License along with this program; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17  * Boston, MA  02110-1301  USA
18  *
19  * Authors: Xavier Claessens <xclaesse@gmail.com>
20  */
21
22 #include <config.h>
23
24 #include <stdlib.h>
25 #include <errno.h>
26 #include <string.h>
27
28 #include <glib.h>
29 #include <glib/gstdio.h>
30 #include <glib/gi18n.h>
31 #include <gtk/gtk.h>
32 #include <gdk/gdkx.h>
33
34 #ifdef HAVE_LIBCHAMPLAIN
35 #include <clutter-gtk/clutter-gtk.h>
36 #endif
37
38 #include <libnotify/notify.h>
39
40 #include <telepathy-glib/account-manager.h>
41 #include <telepathy-glib/dbus.h>
42 #include <telepathy-glib/debug-sender.h>
43 #include <telepathy-glib/util.h>
44 #include <telepathy-glib/connection-manager.h>
45 #include <telepathy-glib/interfaces.h>
46
47 #if HAVE_CALL
48  #include <telepathy-yell/telepathy-yell.h>
49 #endif
50
51 #include <telepathy-logger/log-manager.h>
52
53 #include <libempathy/empathy-presence-manager.h>
54 #include <libempathy/empathy-utils.h>
55 #include <libempathy/empathy-chatroom-manager.h>
56 #include <libempathy/empathy-account-settings.h>
57 #include <libempathy/empathy-connectivity.h>
58 #include <libempathy/empathy-connection-managers.h>
59 #include <libempathy/empathy-request-util.h>
60 #include <libempathy/empathy-ft-factory.h>
61 #include <libempathy/empathy-gsettings.h>
62 #include <libempathy/empathy-tp-chat.h>
63
64 #include <libempathy-gtk/empathy-ui-utils.h>
65 #include <libempathy-gtk/empathy-location-manager.h>
66
67 #include "empathy-main-window.h"
68 #include "empathy-accounts-common.h"
69 #include "empathy-accounts-dialog.h"
70 #include "empathy-status-icon.h"
71 #include "empathy-ft-manager.h"
72 #include "empathy-notifications-approver.h"
73
74 #include "extensions/extensions.h"
75
76 #define DEBUG_FLAG EMPATHY_DEBUG_OTHER
77 #include <libempathy/empathy-debug.h>
78
79 #define EMPATHY_DBUS_NAME "org.gnome.Empathy"
80
81 #define EMPATHY_TYPE_APP (empathy_app_get_type ())
82 #define EMPATHY_APP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EMPATHY_TYPE_APP, EmpathyApp))
83 #define EMPATHY_APP_CLASS(obj) (G_TYPE_CHECK_CLASS_CAST ((obj), EMPATHY_TYPE_APP, EmpathyAppClass))
84 #define EMPATHY_IS_EMPATHY_APP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EMPATHY_TYPE_APP))
85 #define EMPATHY_IS_EMPATHY_APP_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE ((obj), EMPATHY_TYPE_APP))
86 #define EMPATHY_APP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EMPATHY_TYPE_APP, EmpathyAppClass))
87
88 typedef struct _EmpathyApp EmpathyApp;
89 typedef struct _EmpathyAppClass EmpathyAppClass;
90
91 enum
92 {
93   PROP_NO_CONNECT = 1,
94   PROP_START_HIDDEN
95 };
96
97 GType empathy_app_get_type (void);
98
99 struct _EmpathyAppClass
100 {
101   GtkApplicationClass parent_class;
102 };
103
104 struct _EmpathyApp
105 {
106   GtkApplication parent;
107
108   /* Properties */
109   gboolean no_connect;
110   gboolean start_hidden;
111
112   gboolean activated;
113
114   GtkWidget *window;
115   EmpathyStatusIcon *icon;
116   TpAccountManager *account_manager;
117   TplLogManager *log_manager;
118   EmpathyChatroomManager *chatroom_manager;
119   EmpathyFTFactory  *ft_factory;
120   EmpathyPresenceManager *presence_mgr;
121   EmpathyConnectivity *connectivity;
122   GSettings *gsettings;
123   EmpathyNotificationsApprover *notifications_approver;
124 #ifdef HAVE_GEOCLUE
125   EmpathyLocationManager *location_manager;
126 #endif
127 #ifdef ENABLE_DEBUG
128   TpDebugSender *debug_sender;
129 #endif
130 };
131
132
133 G_DEFINE_TYPE(EmpathyApp, empathy_app, GTK_TYPE_APPLICATION)
134
135 static void
136 empathy_app_dispose (GObject *object)
137 {
138   EmpathyApp *self = EMPATHY_APP (object);
139   void (*dispose) (GObject *) =
140     G_OBJECT_CLASS (empathy_app_parent_class)->dispose;
141
142   if (self->presence_mgr != NULL)
143     {
144       empathy_presence_manager_set_state (self->presence_mgr,
145           TP_CONNECTION_PRESENCE_TYPE_OFFLINE);
146     }
147
148 #ifdef ENABLE_DEBUG
149   tp_clear_object (&self->debug_sender);
150 #endif
151
152   tp_clear_object (&self->presence_mgr);
153   tp_clear_object (&self->connectivity);
154   tp_clear_object (&self->icon);
155   tp_clear_object (&self->account_manager);
156   tp_clear_object (&self->log_manager);
157   tp_clear_object (&self->chatroom_manager);
158 #ifdef HAVE_GEOCLUE
159   tp_clear_object (&self->location_manager);
160 #endif
161   tp_clear_object (&self->ft_factory);
162   tp_clear_object (&self->gsettings);
163   tp_clear_object (&self->notifications_approver);
164
165   if (dispose != NULL)
166     dispose (object);
167 }
168
169 static void
170 empathy_app_finalize (GObject *object)
171 {
172   EmpathyApp *self = EMPATHY_APP (object);
173   void (*finalize) (GObject *) =
174     G_OBJECT_CLASS (empathy_app_parent_class)->finalize;
175
176   if (self->window != NULL)
177     gtk_widget_destroy (self->window);
178
179   if (finalize != NULL)
180     finalize (object);
181 }
182
183 static void account_manager_ready_cb (GObject *source_object,
184     GAsyncResult *result,
185     gpointer user_data);
186
187 static void
188 empathy_app_set_property (GObject *object,
189     guint prop_id,
190     const GValue *value,
191     GParamSpec *pspec)
192 {
193   EmpathyApp *self = EMPATHY_APP (object);
194
195   switch (prop_id)
196     {
197       case PROP_NO_CONNECT:
198         self->no_connect = g_value_get_boolean (value);
199         break;
200       case PROP_START_HIDDEN:
201         self->start_hidden = g_value_get_boolean (value);
202         break;
203       default:
204         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
205         break;
206     }
207 }
208
209 static void
210 new_incoming_transfer_cb (EmpathyFTFactory *factory,
211     EmpathyFTHandler *handler,
212     GError *error,
213     gpointer user_data)
214 {
215   if (error)
216     empathy_ft_manager_display_error (handler, error);
217   else
218     empathy_receive_file_with_file_chooser (handler);
219 }
220
221 static void
222 new_ft_handler_cb (EmpathyFTFactory *factory,
223     EmpathyFTHandler *handler,
224     GError *error,
225     gpointer user_data)
226 {
227   if (error)
228     empathy_ft_manager_display_error (handler, error);
229   else
230     empathy_ft_manager_add_handler (handler);
231
232   g_object_unref (handler);
233 }
234
235 static int
236 empathy_app_command_line (GApplication *app,
237     GApplicationCommandLine *cmdline)
238 {
239   EmpathyApp *self = (EmpathyApp *) app;
240
241   if (!self->activated)
242     {
243       GError *error = NULL;
244
245       /* Create the FT factory */
246       self->ft_factory = empathy_ft_factory_dup_singleton ();
247       g_signal_connect (self->ft_factory, "new-ft-handler",
248           G_CALLBACK (new_ft_handler_cb), NULL);
249       g_signal_connect (self->ft_factory, "new-incoming-transfer",
250           G_CALLBACK (new_incoming_transfer_cb), NULL);
251
252       if (!empathy_ft_factory_register (self->ft_factory, &error))
253         {
254           g_warning ("Failed to register FileTransfer handler: %s",
255               error->message);
256           g_error_free (error);
257         }
258
259       g_application_hold (G_APPLICATION (app));
260       self->activated = TRUE;
261
262       /* Setting up UI */
263       self->window = empathy_main_window_dup ();
264       self->icon = empathy_status_icon_new (GTK_WINDOW (self->window),
265           self->start_hidden);
266
267       self->notifications_approver =
268         empathy_notifications_approver_dup_singleton ();
269     }
270   else
271     {
272       /* We're requested to show stuff again, disable the start hidden global in
273        * case the accounts wizard wants to pop up.
274        */
275       self->start_hidden = FALSE;
276     }
277
278   if (!self->start_hidden)
279     empathy_window_present (GTK_WINDOW (self->window));
280
281   /* Display the accounts dialog if needed */
282   tp_account_manager_prepare_async (self->account_manager, NULL,
283       account_manager_ready_cb, self);
284
285   return 0;
286 }
287
288 static gboolean
289 show_version_cb (const char *option_name,
290     const char *value,
291     gpointer data,
292     GError **error);
293
294 static gboolean
295 empathy_app_local_command_line (GApplication *app,
296     gchar ***arguments,
297     gint *exit_status)
298 {
299   EmpathyApp *self = (EmpathyApp *) app;
300   gint i;
301   gchar **argv;
302   gint argc = 0;
303   gboolean retval = FALSE;
304   GError *error = NULL;
305   gboolean no_connect = FALSE, start_hidden = FALSE;
306
307   GOptionContext *optcontext;
308   GOptionEntry options[] = {
309       { "no-connect", 'n',
310         0, G_OPTION_ARG_NONE, &no_connect,
311         N_("Don't connect on startup"),
312         NULL },
313       { "start-hidden", 'h',
314         0, G_OPTION_ARG_NONE, &start_hidden,
315         N_("Don't display the contact list or any other dialogs on startup"),
316         NULL },
317       { "version", 'v',
318         G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, show_version_cb,
319         NULL, NULL },
320       { NULL }
321   };
322
323   optcontext = g_option_context_new (N_("- Empathy IM Client"));
324   g_option_context_add_group (optcontext, gtk_get_option_group (TRUE));
325   g_option_context_add_main_entries (optcontext, options, GETTEXT_PACKAGE);
326
327   argv = *arguments;
328   for (i = 0; argv[i] != NULL; i++)
329     argc++;
330
331   if (!g_option_context_parse (optcontext, &argc, &argv, &error))
332     {
333       g_print ("%s\nRun '%s --help' to see a full list of available command "
334           "line options.\n",
335           error->message, argv[0]);
336       g_warning ("Error in empathy init: %s", error->message);
337
338       *exit_status = EXIT_FAILURE;
339       retval = TRUE;
340     }
341
342   g_option_context_free (optcontext);
343
344   self->no_connect = no_connect;
345   self->start_hidden = start_hidden;
346
347   return retval;
348 }
349
350 static void empathy_app_constructed (GObject *object);
351
352 static void
353 empathy_app_class_init (EmpathyAppClass *klass)
354 {
355   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
356   GApplicationClass *g_app_class = G_APPLICATION_CLASS (klass);
357   GParamSpec *spec;
358
359   gobject_class->set_property = empathy_app_set_property;
360   gobject_class->constructed = empathy_app_constructed;
361   gobject_class->dispose = empathy_app_dispose;
362   gobject_class->finalize = empathy_app_finalize;
363
364   g_app_class->command_line = empathy_app_command_line;
365   g_app_class->local_command_line = empathy_app_local_command_line;
366
367   spec = g_param_spec_boolean ("no-connect", "no connect",
368       "Don't connect on startup",
369       FALSE,
370       G_PARAM_STATIC_STRINGS | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY);
371   g_object_class_install_property (gobject_class, PROP_NO_CONNECT, spec);
372
373   spec = g_param_spec_boolean ("start-hidden", "start hidden",
374       "Don't display the contact list or any other dialogs on startup",
375       FALSE,
376       G_PARAM_STATIC_STRINGS | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY);
377   g_object_class_install_property (gobject_class, PROP_START_HIDDEN, spec);
378 }
379
380 static void
381 empathy_app_init (EmpathyApp *self)
382 {
383 }
384
385 static void
386 use_conn_notify_cb (GSettings *gsettings,
387     const gchar *key,
388     gpointer     user_data)
389 {
390   EmpathyConnectivity *connectivity = user_data;
391
392   empathy_connectivity_set_use_conn (connectivity,
393       g_settings_get_boolean (gsettings, key));
394 }
395
396 static void
397 migrate_config_to_xdg_dir (void)
398 {
399   gchar *xdg_dir, *old_dir, *xdg_filename, *old_filename;
400   int i;
401   GFile *xdg_file, *old_file;
402   static const gchar* filenames[] = {
403     "geometry.ini",
404     "irc-networks.xml",
405     "chatrooms.xml",
406     "contact-groups.xml",
407     "status-presets.xml",
408     "accels.txt",
409     NULL
410   };
411
412   xdg_dir = g_build_filename (g_get_user_config_dir (), PACKAGE_NAME, NULL);
413   if (g_file_test (xdg_dir, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))
414     {
415       /* xdg config dir already exists */
416       g_free (xdg_dir);
417       return;
418     }
419
420   old_dir = g_build_filename (g_get_home_dir (), ".gnome2",
421       PACKAGE_NAME, NULL);
422   if (!g_file_test (old_dir, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))
423     {
424       /* old config dir didn't exist */
425       g_free (xdg_dir);
426       g_free (old_dir);
427       return;
428     }
429
430   if (g_mkdir_with_parents (xdg_dir, (S_IRUSR | S_IWUSR | S_IXUSR)) == -1)
431     {
432       DEBUG ("Failed to create configuration directory; aborting migration");
433       g_free (xdg_dir);
434       g_free (old_dir);
435       return;
436     }
437
438   for (i = 0; filenames[i]; i++)
439     {
440       old_filename = g_build_filename (old_dir, filenames[i], NULL);
441       if (!g_file_test (old_filename, G_FILE_TEST_EXISTS))
442         {
443           g_free (old_filename);
444           continue;
445         }
446       xdg_filename = g_build_filename (xdg_dir, filenames[i], NULL);
447       old_file = g_file_new_for_path (old_filename);
448       xdg_file = g_file_new_for_path (xdg_filename);
449
450       if (!g_file_move (old_file, xdg_file, G_FILE_COPY_NONE,
451           NULL, NULL, NULL, NULL))
452         DEBUG ("Failed to migrate %s", filenames[i]);
453
454       g_free (old_filename);
455       g_free (xdg_filename);
456       g_object_unref (old_file);
457       g_object_unref (xdg_file);
458     }
459
460   g_free (xdg_dir);
461   g_free (old_dir);
462 }
463
464 static void
465 show_accounts_ui (EmpathyApp *self,
466     GdkScreen *screen,
467     gboolean if_needed)
468 {
469   empathy_accounts_dialog_show_application (screen,
470       NULL, if_needed, self->start_hidden);
471 }
472
473 static gboolean
474 show_version_cb (const char *option_name,
475     const char *value,
476     gpointer data,
477     GError **error)
478 {
479   g_print ("%s\n", PACKAGE_STRING);
480
481   exit (EXIT_SUCCESS);
482 }
483
484 static void
485 account_manager_ready_cb (GObject *source_object,
486     GAsyncResult *result,
487     gpointer user_data)
488 {
489   TpAccountManager *manager = TP_ACCOUNT_MANAGER (source_object);
490   EmpathyApp *self = user_data;
491   GError *error = NULL;
492   TpConnectionPresenceType presence;
493
494   if (!tp_account_manager_prepare_finish (manager, result, &error))
495     {
496       GtkWidget *dialog;
497
498       DEBUG ("Failed to prepare account manager: %s", error->message);
499
500       dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL,
501           GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
502           _("Error contacting the Account Manager"));
503       gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
504           _("There was an error while trying to connect to the Telepathy "
505             "Account Manager. The error was:\n\n%s"),
506           error->message);
507
508       gtk_dialog_run (GTK_DIALOG (dialog));
509       gtk_widget_destroy (dialog);
510
511       g_error_free (error);
512       return;
513     }
514
515   /* Autoconnect */
516   presence = tp_account_manager_get_most_available_presence (manager, NULL,
517       NULL);
518
519   if (g_settings_get_boolean (self->gsettings, EMPATHY_PREFS_AUTOCONNECT) &&
520       !self->no_connect &&
521       tp_connection_presence_type_cmp_availability
522           (presence, TP_CONNECTION_PRESENCE_TYPE_OFFLINE)
523             <= 0)
524       /* if current state is Offline, then put it online */
525       empathy_presence_manager_set_state (self->presence_mgr,
526           TP_CONNECTION_PRESENCE_TYPE_AVAILABLE);
527
528   /* Pop up the accounts dialog if we don't have any account */
529   if (!empathy_accounts_has_accounts (manager))
530     show_accounts_ui (self, gdk_screen_get_default (), TRUE);
531 }
532
533 static void
534 account_join_chatrooms (TpAccount *account,
535   EmpathyChatroomManager *chatroom_manager)
536 {
537   TpConnection *conn;
538   GList *chatrooms, *p;
539
540   if (tp_account_get_connection_status (account, NULL) !=
541       TP_CONNECTION_STATUS_CONNECTED)
542     return;
543
544   /* If we're connected we should have a connection */
545   conn = tp_account_get_connection (account);
546   g_return_if_fail (conn != NULL);
547
548   chatrooms = empathy_chatroom_manager_get_chatrooms (
549           chatroom_manager, account);
550
551   for (p = chatrooms; p != NULL; p = p->next)
552     {
553       EmpathyChatroom *room = EMPATHY_CHATROOM (p->data);
554
555       if (!empathy_chatroom_get_auto_connect (room))
556         continue;
557
558       empathy_join_muc (account, empathy_chatroom_get_room (room),
559         TP_USER_ACTION_TIME_NOT_USER_ACTION);
560     }
561   g_list_free (chatrooms);
562 }
563
564 static void
565 account_status_changed_cb (TpAccount *account,
566     guint old_status,
567     guint new_status,
568     guint reason,
569     gchar *dbus_error_name,
570     GHashTable *details,
571     EmpathyChatroomManager *manager)
572 {
573   account_join_chatrooms (account, manager);
574 }
575
576 static void
577 account_manager_chatroom_ready_cb (GObject *source_object,
578     GAsyncResult *result,
579     gpointer user_data)
580 {
581   TpAccountManager *account_manager = TP_ACCOUNT_MANAGER (source_object);
582   EmpathyChatroomManager *chatroom_manager = user_data;
583   GList *accounts, *l;
584   GError *error = NULL;
585
586   if (!tp_account_manager_prepare_finish (account_manager, result, &error))
587     {
588       DEBUG ("Failed to prepare account manager: %s", error->message);
589       g_error_free (error);
590       return;
591     }
592
593   accounts = tp_account_manager_get_valid_accounts (account_manager);
594
595   for (l = accounts; l != NULL; l = g_list_next (l))
596     {
597       TpAccount *account = TP_ACCOUNT (l->data);
598
599       /* Try to join all rooms if we're connected */
600       account_join_chatrooms (account, chatroom_manager);
601
602       /* And/or join them on (re)connection */
603       tp_g_signal_connect_object (account, "status-changed",
604         G_CALLBACK (account_status_changed_cb), chatroom_manager, 0);
605     }
606   g_list_free (accounts);
607 }
608
609 static void
610 chatroom_manager_ready_cb (EmpathyChatroomManager *chatroom_manager,
611     GParamSpec *pspec,
612     gpointer user_data)
613 {
614   TpAccountManager *account_manager = user_data;
615
616   tp_account_manager_prepare_async (account_manager, NULL,
617       account_manager_chatroom_ready_cb, chatroom_manager);
618 }
619
620 static void
621 empathy_presence_manager_set_auto_away_cb (GSettings *gsettings,
622                                 const gchar *key,
623                                 gpointer user_data)
624 {
625         EmpathyPresenceManager *presence_mgr = user_data;
626
627         empathy_presence_manager_set_auto_away (presence_mgr,
628       g_settings_get_boolean (gsettings, key));
629 }
630
631 static void
632 empathy_app_constructed (GObject *object)
633 {
634   EmpathyApp *self = (EmpathyApp *) object;
635   gboolean chatroom_manager_ready;
636   gboolean autoaway;
637
638   g_set_application_name (_(PACKAGE_NAME));
639
640   gtk_window_set_default_icon_name ("empathy");
641   textdomain (GETTEXT_PACKAGE);
642
643 #ifdef ENABLE_DEBUG
644   /* Set up debug sender */
645   self->debug_sender = tp_debug_sender_dup ();
646   g_log_set_default_handler (tp_debug_sender_log_handler, G_LOG_DOMAIN);
647 #endif
648
649   notify_init (_(PACKAGE_NAME));
650
651   /* Setting up Idle */
652   self->presence_mgr = empathy_presence_manager_dup_singleton ();
653
654   self->gsettings = g_settings_new (EMPATHY_PREFS_SCHEMA);
655   autoaway = g_settings_get_boolean (self->gsettings, EMPATHY_PREFS_AUTOAWAY);
656
657   g_signal_connect (self->gsettings,
658       "changed::" EMPATHY_PREFS_AUTOAWAY,
659       G_CALLBACK (empathy_presence_manager_set_auto_away_cb),
660       self->presence_mgr);
661
662   empathy_presence_manager_set_auto_away (self->presence_mgr, autoaway);
663
664   /* Setting up Connectivity */
665   self->connectivity = empathy_connectivity_dup_singleton ();
666   use_conn_notify_cb (self->gsettings, EMPATHY_PREFS_USE_CONN,
667       self->connectivity);
668   g_signal_connect (self->gsettings,
669       "changed::" EMPATHY_PREFS_USE_CONN,
670       G_CALLBACK (use_conn_notify_cb), self->connectivity);
671
672   /* account management */
673   self->account_manager = tp_account_manager_dup ();
674   tp_account_manager_prepare_async (self->account_manager, NULL,
675       account_manager_ready_cb, self);
676
677   migrate_config_to_xdg_dir ();
678
679   /* Logging */
680   self->log_manager = tpl_log_manager_dup_singleton ();
681
682   self->chatroom_manager = empathy_chatroom_manager_dup_singleton (NULL);
683
684   g_object_get (self->chatroom_manager, "ready", &chatroom_manager_ready, NULL);
685   if (!chatroom_manager_ready)
686     {
687       g_signal_connect (G_OBJECT (self->chatroom_manager), "notify::ready",
688           G_CALLBACK (chatroom_manager_ready_cb), self->account_manager);
689     }
690   else
691     {
692       chatroom_manager_ready_cb (self->chatroom_manager, NULL,
693           self->account_manager);
694     }
695
696   /* Location mananger */
697 #ifdef HAVE_GEOCLUE
698   self->location_manager = empathy_location_manager_dup_singleton ();
699 #endif
700
701   self->activated = FALSE;
702   self->ft_factory = NULL;
703   self->window = NULL;
704 }
705
706 int
707 main (int argc, char *argv[])
708 {
709   EmpathyApp *app;
710   gint retval;
711
712   g_thread_init (NULL);
713   g_type_init ();
714
715 #ifdef HAVE_LIBCHAMPLAIN
716   gtk_clutter_init (&argc, &argv);
717 #endif
718
719   tpy_cli_init ();
720
721   empathy_init ();
722   gtk_init (&argc, &argv);
723   empathy_gtk_init ();
724
725   app = g_object_new (EMPATHY_TYPE_APP,
726       "application-id", EMPATHY_DBUS_NAME,
727       "flags", G_APPLICATION_HANDLES_COMMAND_LINE,
728       NULL);
729
730   retval = g_application_run (G_APPLICATION (app), argc, argv);
731
732   notify_uninit ();
733   xmlCleanupParser ();
734
735   g_object_unref (app);
736
737   return retval;
738 }