comparison gtk/gtkmain.c @ 14191:009db0b357b5

This is a hand-crafted commit to migrate across subversion revisions 16854:16861, due to some vagaries of the way the original renames were done. Witness that monotone can do in one revision what svn had to spread across several.
author Ethan Blanton <elb@pidgin.im>
date Sat, 16 Dec 2006 04:59:55 +0000
parents
children ab8a105eff62
comparison
equal deleted inserted replaced
14190:366be2ce35a7 14191:009db0b357b5
1 /*
2 * gaim
3 *
4 * Gaim is the legal property of its developers, whose names are too numerous
5 * to list here. Please refer to the COPYRIGHT file distributed with this
6 * source distribution.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 */
23
24 #include "internal.h"
25 #include "gtkgaim.h"
26
27 #include "account.h"
28 #include "conversation.h"
29 #include "core.h"
30 #include "debug.h"
31 #include "eventloop.h"
32 #include "ft.h"
33 #include "log.h"
34 #include "notify.h"
35 #include "prefs.h"
36 #include "prpl.h"
37 #include "pounce.h"
38 #include "sound.h"
39 #include "status.h"
40 #include "util.h"
41 #include "whiteboard.h"
42
43 #include "gtkaccount.h"
44 #include "gtkblist.h"
45 #include "gtkconn.h"
46 #include "gtkconv.h"
47 #include "gtkdebug.h"
48 #include "gtkdialogs.h"
49 #include "gtkeventloop.h"
50 #include "gtkft.h"
51 #include "gtkidle.h"
52 #include "gtklog.h"
53 #include "gtknotify.h"
54 #include "gtkplugin.h"
55 #include "gtkpounce.h"
56 #include "gtkprefs.h"
57 #include "gtkprivacy.h"
58 #include "gtkrequest.h"
59 #include "gtkroomlist.h"
60 #include "gtksavedstatuses.h"
61 #include "gtksession.h"
62 #include "gtksound.h"
63 #include "gtkthemes.h"
64 #include "gtkutils.h"
65 #include "gaimstock.h"
66 #include "gtkwhiteboard.h"
67
68 #ifdef HAVE_SIGNAL_H
69 # include <signal.h>
70 #endif
71
72 #include <getopt.h>
73
74 #ifdef HAVE_STARTUP_NOTIFICATION
75 # define SN_API_NOT_YET_FROZEN
76 # include <libsn/sn-launchee.h>
77 # include <gdk/gdkx.h>
78 #endif
79
80 #ifdef _WIN32
81 # include "wspell.h"
82 #endif
83
84
85
86 #ifdef HAVE_STARTUP_NOTIFICATION
87 static SnLauncheeContext *sn_context = NULL;
88 static SnDisplay *sn_display = NULL;
89 #endif
90
91 #ifdef HAVE_SIGNAL_H
92 /*
93 * Lists of signals we wish to catch and those we wish to ignore.
94 * Each list terminated with -1
95 */
96 static int catch_sig_list[] = {
97 SIGSEGV,
98 SIGHUP,
99 SIGINT,
100 SIGTERM,
101 SIGQUIT,
102 SIGCHLD,
103 -1
104 };
105
106 static int ignore_sig_list[] = {
107 SIGPIPE,
108 -1
109 };
110 #endif
111
112 static int
113 dologin_named(const char *name)
114 {
115 GaimAccount *account;
116 char **names;
117 int i;
118 int ret = -1;
119
120 if (name != NULL) { /* list of names given */
121 names = g_strsplit(name, ",", 64);
122 for (i = 0; names[i] != NULL; i++) {
123 account = gaim_accounts_find(names[i], NULL);
124 if (account != NULL) { /* found a user */
125 ret = 0;
126 gaim_account_connect(account);
127 }
128 }
129 g_strfreev(names);
130 } else { /* no name given, use the first account */
131 GList *accounts;
132
133 accounts = gaim_accounts_get_all();
134 if (accounts != NULL)
135 {
136 account = (GaimAccount *)accounts->data;
137 ret = 0;
138 gaim_account_connect(account);
139 }
140 }
141
142 return ret;
143 }
144
145 #ifdef HAVE_SIGNAL_H
146 static void
147 clean_pid(void)
148 {
149 int status;
150 pid_t pid;
151
152 do {
153 pid = waitpid(-1, &status, WNOHANG);
154 } while (pid != 0 && pid != (pid_t)-1);
155
156 if ((pid == (pid_t) - 1) && (errno != ECHILD)) {
157 char errmsg[BUFSIZ];
158 snprintf(errmsg, BUFSIZ, "Warning: waitpid() returned %d", pid);
159 perror(errmsg);
160 }
161 }
162
163 char *segfault_message;
164
165 static void
166 sighandler(int sig)
167 {
168 switch (sig) {
169 case SIGHUP:
170 gaim_debug_warning("sighandler", "Caught signal %d\n", sig);
171 gaim_connections_disconnect_all();
172 break;
173 case SIGSEGV:
174 fprintf(stderr, "%s", segfault_message);
175 abort();
176 break;
177 case SIGCHLD:
178 clean_pid();
179 signal(SIGCHLD, sighandler); /* restore signal catching on this one! */
180 break;
181 default:
182 gaim_debug_warning("sighandler", "Caught signal %d\n", sig);
183 gaim_connections_disconnect_all();
184
185 gaim_plugins_unload_all();
186
187 if (gtk_main_level())
188 gtk_main_quit();
189 exit(0);
190 }
191 }
192 #endif
193
194 static int
195 ui_main()
196 {
197 #ifndef _WIN32
198 GList *icons = NULL;
199 GdkPixbuf *icon = NULL;
200 char *icon_path;
201 #endif
202
203 gaim_gtkthemes_init();
204
205 gaim_gtk_blist_setup_sort_methods();
206
207 #ifndef _WIN32
208 /* use the nice PNG icon for all the windows */
209 icon_path = g_build_filename(DATADIR, "pixmaps", "gaim", "icons", "online.png", NULL);
210 icon = gdk_pixbuf_new_from_file(icon_path, NULL);
211 g_free(icon_path);
212 if (icon) {
213 icons = g_list_append(icons,icon);
214 gtk_window_set_default_icon_list(icons);
215 g_object_unref(G_OBJECT(icon));
216 g_list_free(icons);
217 } else {
218 gaim_debug_error("ui_main",
219 "Failed to load the default window icon!\n");
220 }
221 #endif
222
223 return 0;
224 }
225
226 static void
227 debug_init(void)
228 {
229 gaim_debug_set_ui_ops(gaim_gtk_debug_get_ui_ops());
230 gaim_gtk_debug_init();
231 }
232
233 static void
234 gaim_gtk_ui_init(void)
235 {
236 /* Set the UI operation structures. */
237 gaim_accounts_set_ui_ops(gaim_gtk_accounts_get_ui_ops());
238 gaim_xfers_set_ui_ops(gaim_gtk_xfers_get_ui_ops());
239 gaim_blist_set_ui_ops(gaim_gtk_blist_get_ui_ops());
240 gaim_notify_set_ui_ops(gaim_gtk_notify_get_ui_ops());
241 gaim_privacy_set_ui_ops(gaim_gtk_privacy_get_ui_ops());
242 gaim_request_set_ui_ops(gaim_gtk_request_get_ui_ops());
243 gaim_sound_set_ui_ops(gaim_gtk_sound_get_ui_ops());
244 gaim_connections_set_ui_ops(gaim_gtk_connections_get_ui_ops());
245 gaim_whiteboard_set_ui_ops(gaim_gtk_whiteboard_get_ui_ops());
246 #ifdef USE_SCREENSAVER
247 gaim_idle_set_ui_ops(gaim_gtk_idle_get_ui_ops());
248 #endif
249
250 gaim_gtk_stock_init();
251 gaim_gtk_account_init();
252 gaim_gtk_connection_init();
253 gaim_gtk_blist_init();
254 gaim_gtk_status_init();
255 gaim_gtk_conversations_init();
256 gaim_gtk_pounces_init();
257 gaim_gtk_privacy_init();
258 gaim_gtk_xfers_init();
259 gaim_gtk_roomlist_init();
260 gaim_gtk_log_init();
261 }
262
263 static void
264 gaim_gtk_quit(void)
265 {
266 #ifdef USE_SM
267 /* unplug */
268 gaim_gtk_session_end();
269 #endif
270
271 /* Save the plugins we have loaded for next time. */
272 gaim_gtk_plugins_save();
273
274 /* Uninit */
275 gaim_gtk_conversations_uninit();
276 gaim_gtk_status_uninit();
277 gaim_gtk_blist_uninit();
278 gaim_gtk_connection_uninit();
279 gaim_gtk_account_uninit();
280 gaim_gtk_xfers_uninit();
281 gaim_gtk_debug_uninit();
282
283 /* and end it all... */
284 gtk_main_quit();
285 }
286
287 static GaimCoreUiOps core_ops =
288 {
289 gaim_gtk_prefs_init,
290 debug_init,
291 gaim_gtk_ui_init,
292 gaim_gtk_quit
293 };
294
295 static GaimCoreUiOps *
296 gaim_gtk_core_get_ui_ops(void)
297 {
298 return &core_ops;
299 }
300
301 static void
302 show_usage(const char *name, gboolean terse)
303 {
304 char *text;
305
306 if (terse) {
307 text = g_strdup_printf(_("Gaim %s. Try `%s -h' for more information.\n"), VERSION, name);
308 } else {
309 text = g_strdup_printf(_("Gaim %s\n"
310 "Usage: %s [OPTION]...\n\n"
311 " -c, --config=DIR use DIR for config files\n"
312 " -d, --debug print debugging messages to stdout\n"
313 " -h, --help display this help and exit\n"
314 " -n, --nologin don't automatically login\n"
315 " -l, --login[=NAME] automatically login (optional argument NAME specifies\n"
316 " account(s) to use, separated by commas)\n"
317 " -v, --version display the current version and exit\n"), VERSION, name);
318 }
319
320 gaim_print_utf8_to_console(stdout, text);
321 g_free(text);
322 }
323
324 #ifdef HAVE_STARTUP_NOTIFICATION
325 static void
326 sn_error_trap_push(SnDisplay *display, Display *xdisplay)
327 {
328 gdk_error_trap_push();
329 }
330
331 static void
332 sn_error_trap_pop(SnDisplay *display, Display *xdisplay)
333 {
334 gdk_error_trap_pop();
335 }
336
337 static void
338 startup_notification_complete(void)
339 {
340 Display *xdisplay;
341
342 xdisplay = GDK_DISPLAY();
343 sn_display = sn_display_new(xdisplay,
344 sn_error_trap_push,
345 sn_error_trap_pop);
346 sn_context =
347 sn_launchee_context_new_from_environment(sn_display,
348 DefaultScreen(xdisplay));
349
350 if (sn_context != NULL)
351 {
352 sn_launchee_context_complete(sn_context);
353 sn_launchee_context_unref(sn_context);
354
355 sn_display_unref(sn_display);
356 }
357 }
358 #endif /* HAVE_STARTUP_NOTIFICATION */
359
360 #ifndef _WIN32
361 static char *gaim_find_binary_location(void *symbol, void *data)
362 {
363 static char *fullname = NULL;
364 static gboolean first = TRUE;
365
366 char *argv0 = data;
367 struct stat st;
368 char *basebuf, *linkbuf, *fullbuf;
369
370 if (!first)
371 /* We've already been through this. */
372 return strdup(fullname);
373
374 first = FALSE;
375
376 if (!argv0)
377 return NULL;
378
379
380 basebuf = g_find_program_in_path(argv0);
381
382 /* But we still need to deal with symbolic links */
383 g_lstat(basebuf, &st);
384 while ((st.st_mode & S_IFLNK) == S_IFLNK) {
385 int written;
386 linkbuf = g_malloc(1024);
387 written = readlink(basebuf, linkbuf, 1024 - 1);
388 if (written == -1)
389 {
390 /* This really shouldn't happen, but do we
391 * need something better here? */
392 g_free(linkbuf);
393 continue;
394 }
395 linkbuf[written] = '\0';
396 if (linkbuf[0] == G_DIR_SEPARATOR) {
397 /* an absolute path */
398 fullbuf = g_strdup(linkbuf);
399 } else {
400 char *dirbuf = g_path_get_dirname(basebuf);
401 /* a relative path */
402 fullbuf = g_strdup_printf("%s%s%s",
403 dirbuf, G_DIR_SEPARATOR_S,
404 linkbuf);
405 g_free(dirbuf);
406 }
407 /* There's no memory leak here. Really! */
408 g_free(linkbuf);
409 g_free(basebuf);
410 basebuf = fullbuf;
411 g_lstat(basebuf, &st);
412 }
413
414 fullname = basebuf;
415 return strdup(fullname);
416 }
417 #endif /* #ifndef _WIN32 */
418
419 /* FUCKING GET ME A TOWEL! */
420 #ifdef _WIN32
421 int gaim_main(HINSTANCE hint, int argc, char *argv[])
422 #else
423 int main(int argc, char *argv[])
424 #endif
425 {
426 gboolean opt_help = FALSE;
427 gboolean opt_login = FALSE;
428 gboolean opt_nologin = FALSE;
429 gboolean opt_version = FALSE;
430 char *opt_config_dir_arg = NULL;
431 char *opt_login_arg = NULL;
432 char *opt_session_arg = NULL;
433 int dologin_ret = -1;
434 char *search_path;
435 GList *accounts;
436 #ifdef HAVE_SIGNAL_H
437 int sig_indx; /* for setting up signal catching */
438 sigset_t sigset;
439 RETSIGTYPE (*prev_sig_disp)(int);
440 #endif
441 int opt;
442 gboolean gui_check;
443 gboolean debug_enabled;
444 #ifdef HAVE_SIGNAL_H
445 char errmsg[BUFSIZ];
446 #ifndef DEBUG
447 char *segfault_message_tmp;
448 GError *error = NULL;
449 #endif
450 #endif
451
452 struct option long_options[] = {
453 {"config", required_argument, NULL, 'c'},
454 {"debug", no_argument, NULL, 'd'},
455 {"help", no_argument, NULL, 'h'},
456 {"login", optional_argument, NULL, 'l'},
457 {"nologin", no_argument, NULL, 'n'},
458 {"session", required_argument, NULL, 's'},
459 {"version", no_argument, NULL, 'v'},
460 {0, 0, 0, 0}
461 };
462
463 #ifdef DEBUG
464 debug_enabled = TRUE;
465 #else
466 debug_enabled = FALSE;
467 #endif
468
469 #ifdef GAIM_FATAL_ASSERTS
470 /* Make g_return_... functions fatal. */
471 g_log_set_always_fatal(G_LOG_LEVEL_CRITICAL);
472 #endif
473
474 #ifndef _WIN32
475 br_set_locate_fallback_func(gaim_find_binary_location, argv[0]);
476 #endif
477 #ifdef ENABLE_NLS
478 bindtextdomain(PACKAGE, LOCALEDIR);
479 bind_textdomain_codeset(PACKAGE, "UTF-8");
480 textdomain(PACKAGE);
481 #endif
482
483 #ifdef HAVE_SETLOCALE
484 /* Locale initialization is not complete here. See gtk_init_check() */
485 setlocale(LC_ALL, "");
486 #endif
487
488 #ifdef HAVE_SIGNAL_H
489
490 #ifndef DEBUG
491 /* We translate this here in case the crash breaks gettext. */
492 segfault_message_tmp = g_strdup_printf(_(
493 "Gaim has segfaulted and attempted to dump a core file.\n"
494 "This is a bug in the software and has happened through\n"
495 "no fault of your own.\n\n"
496 "If you can reproduce the crash, please notify the gaim\n"
497 "developers by reporting a bug at\n"
498 "%sbug.php\n\n"
499 "Please make sure to specify what you were doing at the time\n"
500 "and post the backtrace from the core file. If you do not know\n"
501 "how to get the backtrace, please read the instructions at\n"
502 "%sgdb.php\n\n"
503 "If you need further assistance, please IM either SeanEgn or \n"
504 "LSchiere (via AIM). Contact information for Sean and Luke \n"
505 "on other protocols is at\n"
506 "%scontactinfo.php\n"),
507 GAIM_WEBSITE, GAIM_WEBSITE, GAIM_WEBSITE
508 );
509
510 /* we have to convert the message (UTF-8 to console
511 charset) early because after a segmentation fault
512 it's not a good practice to allocate memory */
513 segfault_message = g_locale_from_utf8(segfault_message_tmp,
514 -1, NULL, NULL, &error);
515 if (segfault_message != NULL) {
516 g_free(segfault_message_tmp);
517 }
518 else {
519 /* use 'segfault_message_tmp' (UTF-8) as a fallback */
520 g_warning("%s\n", error->message);
521 g_error_free(error);
522 segfault_message = segfault_message_tmp;
523 }
524 #else
525 /* Don't mark this for translation. */
526 segfault_message = g_strdup(
527 "Hi, user. We need to talk.\n"
528 "I think something's gone wrong here. It's probably my fault.\n"
529 "No, really, it's not you... it's me... no no no, I think we get along well\n"
530 "it's just that.... well, I want to see other people. I... what?!? NO! I \n"
531 "haven't been cheating on you!! How many times do you want me to tell you?! And\n"
532 "for the last time, it's just a rash!\n"
533 );
534 #endif
535
536 /* Let's not violate any PLA's!!!! */
537 /* jseymour: whatever the fsck that means */
538 /* Robot101: for some reason things like gdm like to block *
539 * useful signals like SIGCHLD, so we unblock all the ones we *
540 * declare a handler for. thanks JSeymour and Vann. */
541 if (sigemptyset(&sigset)) {
542 snprintf(errmsg, BUFSIZ, "Warning: couldn't initialise empty signal set");
543 perror(errmsg);
544 }
545 for(sig_indx = 0; catch_sig_list[sig_indx] != -1; ++sig_indx) {
546 if((prev_sig_disp = signal(catch_sig_list[sig_indx], sighandler)) == SIG_ERR) {
547 snprintf(errmsg, BUFSIZ, "Warning: couldn't set signal %d for catching",
548 catch_sig_list[sig_indx]);
549 perror(errmsg);
550 }
551 if(sigaddset(&sigset, catch_sig_list[sig_indx])) {
552 snprintf(errmsg, BUFSIZ, "Warning: couldn't include signal %d for unblocking",
553 catch_sig_list[sig_indx]);
554 perror(errmsg);
555 }
556 }
557 for(sig_indx = 0; ignore_sig_list[sig_indx] != -1; ++sig_indx) {
558 if((prev_sig_disp = signal(ignore_sig_list[sig_indx], SIG_IGN)) == SIG_ERR) {
559 snprintf(errmsg, BUFSIZ, "Warning: couldn't set signal %d to ignore",
560 ignore_sig_list[sig_indx]);
561 perror(errmsg);
562 }
563 }
564
565 if (sigprocmask(SIG_UNBLOCK, &sigset, NULL)) {
566 snprintf(errmsg, BUFSIZ, "Warning: couldn't unblock signals");
567 perror(errmsg);
568 }
569 #endif
570
571 /* scan command-line options */
572 opterr = 1;
573 while ((opt = getopt_long(argc, argv,
574 #ifndef _WIN32
575 "c:dhnl::s:v",
576 #else
577 "c:dhnl::v",
578 #endif
579 long_options, NULL)) != -1) {
580 switch (opt) {
581 case 'c': /* config dir */
582 g_free(opt_config_dir_arg);
583 opt_config_dir_arg = g_strdup(optarg);
584 break;
585 case 'd': /* debug */
586 debug_enabled = TRUE;
587 break;
588 case 'h': /* help */
589 opt_help = TRUE;
590 break;
591 case 'n': /* no autologin */
592 opt_nologin = TRUE;
593 break;
594 case 'l': /* login, option username */
595 opt_login = TRUE;
596 g_free(opt_login_arg);
597 if (optarg != NULL)
598 opt_login_arg = g_strdup(optarg);
599 break;
600 case 's': /* use existing session ID */
601 g_free(opt_session_arg);
602 opt_session_arg = g_strdup(optarg);
603 break;
604 case 'v': /* version */
605 opt_version = TRUE;
606 break;
607 case '?': /* show terse help */
608 default:
609 show_usage(argv[0], TRUE);
610 return 0;
611 break;
612 }
613 }
614
615 /* show help message */
616 if (opt_help) {
617 show_usage(argv[0], FALSE);
618 return 0;
619 }
620 /* show version message */
621 if (opt_version) {
622 printf("Gaim %s\n", VERSION);
623 return 0;
624 }
625
626 /* set a user-specified config directory */
627 if (opt_config_dir_arg != NULL) {
628 gaim_util_set_user_dir(opt_config_dir_arg);
629 }
630
631 /*
632 * We're done piddling around with command line arguments.
633 * Fire up this baby.
634 */
635
636 gaim_debug_set_enabled(debug_enabled);
637
638 #ifdef _WIN32
639 wgaim_init(hint);
640 #endif
641
642 search_path = g_build_filename(gaim_user_dir(), "gtkrc-2.0", NULL);
643 gtk_rc_add_default_file(search_path);
644 g_free(search_path);
645
646 #if (defined(G_THREADS_ENABLED) && !defined(G_THREADS_IMPL_NONE))
647 /* Since threads can be yanked in all unawares by other libraries,
648 * and some libraries aren't smart enough to initialize the thread
649 * subsystem when they need it, we need to do this here. We also
650 * threadify dbus when that gets initialized. Ugh. */
651 if (!g_thread_supported())
652 g_thread_init(NULL);
653 #ifndef _WIN32
654 gdk_threads_init();
655 #endif
656 #endif /* Glib has threads */
657
658 gui_check = gtk_init_check(&argc, &argv);
659 if (!gui_check) {
660 char *display = gdk_get_display();
661
662 printf("Gaim %s\n", VERSION);
663
664 g_warning("cannot open display: %s", display ? display : "unset");
665 g_free(display);
666
667 return 1;
668 }
669
670 #ifdef _WIN32
671 /** TODO: Move this to a wgaim_gtk_init() if we need such a thing */
672 wgaim_gtkspell_init();
673 gaim_debug_info("wgaim", "GTK+ :%u.%u.%u\n",
674 gtk_major_version, gtk_minor_version, gtk_micro_version);
675
676 #endif
677
678 gaim_core_set_ui_ops(gaim_gtk_core_get_ui_ops());
679 gaim_eventloop_set_ui_ops(gaim_gtk_eventloop_get_ui_ops());
680
681 /*
682 * Set plugin search directories. Give priority to the plugins
683 * in user's home directory.
684 */
685 search_path = g_build_filename(gaim_user_dir(), "plugins", NULL);
686 gaim_plugins_add_search_path(search_path);
687 g_free(search_path);
688 gaim_plugins_add_search_path(LIBDIR);
689
690 if (!gaim_core_init(GAIM_GTK_UI)) {
691 fprintf(stderr,
692 "Initialization of the Gaim core failed. Dumping core.\n"
693 "Please report this!\n");
694 abort();
695 }
696
697 /* TODO: Move blist loading into gaim_blist_init() */
698 gaim_set_blist(gaim_blist_new());
699 gaim_blist_load();
700
701 /* TODO: Move prefs loading into gaim_prefs_init() */
702 gaim_prefs_load();
703 gaim_prefs_update_old();
704 gaim_gtk_prefs_update_old();
705
706 /* load plugins we had when we quit */
707 gaim_plugins_load_saved("/gaim/gtk/plugins/loaded");
708
709 /* TODO: Move pounces loading into gaim_pounces_init() */
710 gaim_pounces_load();
711
712 ui_main();
713
714 #ifdef USE_SM
715 gaim_gtk_session_init(argv[0], opt_session_arg, opt_config_dir_arg);
716 #endif
717 if (opt_session_arg != NULL) {
718 g_free(opt_session_arg);
719 opt_session_arg = NULL;
720 }
721 if (opt_config_dir_arg != NULL) {
722 g_free(opt_config_dir_arg);
723 opt_config_dir_arg = NULL;
724 }
725
726 /*
727 * We want to show the blist early in the init process so the
728 * user feels warm and fuzzy (not cold and prickley).
729 */
730 gaim_blist_show();
731
732 if (gaim_prefs_get_bool("/gaim/gtk/debug/enabled"))
733 gaim_gtk_debug_window_show();
734
735 if (opt_login) {
736 dologin_ret = dologin_named(opt_login_arg);
737 if (opt_login_arg != NULL) {
738 g_free(opt_login_arg);
739 opt_login_arg = NULL;
740 }
741 }
742
743 if (opt_nologin)
744 {
745 /* Set all accounts to "offline" */
746 GaimSavedStatus *saved_status;
747
748 /* If we've used this type+message before, lookup the transient status */
749 saved_status = gaim_savedstatus_find_transient_by_type_and_message(
750 GAIM_STATUS_OFFLINE, NULL);
751
752 /* If this type+message is unique then create a new transient saved status */
753 if (saved_status == NULL)
754 saved_status = gaim_savedstatus_new(NULL, GAIM_STATUS_OFFLINE);
755
756 /* Set the status for each account */
757 gaim_savedstatus_activate(saved_status);
758 }
759 else
760 {
761 /* Everything is good to go--sign on already */
762 if (!gaim_prefs_get_bool("/core/savedstatus/startup_current_status"))
763 gaim_savedstatus_activate(gaim_savedstatus_get_startup());
764 gaim_accounts_restore_current_statuses();
765 }
766
767 if ((accounts = gaim_accounts_get_all_active()) == NULL)
768 {
769 gaim_gtk_accounts_window_show();
770 }
771 else
772 {
773 g_list_free(accounts);
774 }
775
776 #ifdef HAVE_STARTUP_NOTIFICATION
777 startup_notification_complete();
778 #endif
779
780 gtk_main();
781
782 #ifdef HAVE_SIGNAL_H
783 g_free(segfault_message);
784 #endif
785
786 #ifdef _WIN32
787 wgaim_cleanup();
788 #endif
789
790 return 0;
791 }