Mercurial > pidgin
comparison src/gtkmain.c @ 10302:581de78cf809
[gaim-migrate @ 11487]
Rename main.c to gtkmain.c
Change POTFILES.in to reflect the new file names
Update the po's so they use the new file names
Update the po's to use the correct line numbers (or whatever make dist does)
committer: Tailor Script <tailor@pidgin.im>
author | Mark Doliner <mark@kingant.net> |
---|---|
date | Thu, 02 Dec 2004 23:48:48 +0000 |
parents | |
children | 56cc5d49472b |
comparison
equal
deleted
inserted
replaced
10301:56b53036e48c | 10302:581de78cf809 |
---|---|
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 | |
42 #include "gtkaccount.h" | |
43 #include "gtkblist.h" | |
44 #include "gtkconn.h" | |
45 #include "gtkconv.h" | |
46 #include "gtkdebug.h" | |
47 #include "gtkdialogs.h" | |
48 #include "gtkeventloop.h" | |
49 #include "gtkft.h" | |
50 #include "gtknotify.h" | |
51 #include "gtkplugin.h" | |
52 #include "gtkpounce.h" | |
53 #include "gtkprefs.h" | |
54 #include "gtkprivacy.h" | |
55 #include "gtkrequest.h" | |
56 #include "gtkroomlist.h" | |
57 #include "gtksound.h" | |
58 #include "gtkstatus.h" | |
59 #include "gtkutils.h" | |
60 #include "gtkstock.h" | |
61 | |
62 #if HAVE_SIGNAL_H | |
63 # include <signal.h> | |
64 #endif | |
65 | |
66 #include <getopt.h> | |
67 | |
68 #ifdef HAVE_STARTUP_NOTIFICATION | |
69 # define SN_API_NOT_YET_FROZEN | |
70 # include <libsn/sn-launchee.h> | |
71 # include <gdk/gdkx.h> | |
72 #endif | |
73 | |
74 static GtkWidget *name; | |
75 static GtkWidget *pass; | |
76 | |
77 #ifdef HAVE_STARTUP_NOTIFICATION | |
78 static SnLauncheeContext *sn_context = NULL; | |
79 static SnDisplay *sn_display = NULL; | |
80 #endif | |
81 | |
82 GtkWidget *mainwindow = NULL; | |
83 | |
84 int opt_away = 0; | |
85 int docklet_count = 0; | |
86 char *opt_away_arg = NULL; | |
87 int opt_debug = 0; | |
88 | |
89 #if HAVE_SIGNAL_H | |
90 /* | |
91 * Lists of signals we wish to catch and those we wish to ignore. | |
92 * Each list terminated with -1 | |
93 */ | |
94 static int catch_sig_list[] = { | |
95 SIGSEGV, | |
96 SIGHUP, | |
97 SIGINT, | |
98 SIGTERM, | |
99 SIGQUIT, | |
100 SIGCHLD, | |
101 -1 | |
102 }; | |
103 | |
104 static int ignore_sig_list[] = { | |
105 SIGPIPE, | |
106 -1 | |
107 }; | |
108 #endif | |
109 | |
110 static guint snd_tmout = 0; | |
111 static gboolean sound_timeout(gpointer data) | |
112 { | |
113 gaim_gtk_sound_set_login_mute(FALSE); | |
114 snd_tmout = 0; | |
115 return FALSE; | |
116 } | |
117 | |
118 /* we need to do this for Oscar because serv_login only starts the login | |
119 * process, it doesn't end there. gaim_setup will be called later from | |
120 * oscar.c, after the buddy list is made and serv_finish_login is called */ | |
121 void gaim_setup(GaimConnection *gc) | |
122 { | |
123 if (gaim_prefs_get_bool("/gaim/gtk/sound/enabled/login")) { | |
124 if (snd_tmout) | |
125 g_source_remove(snd_tmout); | |
126 gaim_gtk_sound_set_login_mute(TRUE); | |
127 snd_tmout = gaim_timeout_add(10000, sound_timeout, NULL); | |
128 } | |
129 } | |
130 | |
131 static gboolean domiddleclick(GtkWidget *w, GdkEventButton *event, gpointer null) | |
132 { | |
133 if (event->button != 2) | |
134 return FALSE; | |
135 | |
136 gaim_accounts_auto_login(GAIM_GTK_UI); | |
137 | |
138 return TRUE; | |
139 } | |
140 | |
141 static void dologin(GtkWidget *widget, GtkWidget *w) | |
142 { | |
143 GaimAccount *account; | |
144 GtkWidget *item; | |
145 const char *password = gtk_entry_get_text(GTK_ENTRY(pass)); | |
146 | |
147 item = gtk_menu_get_active(GTK_MENU(gtk_option_menu_get_menu(GTK_OPTION_MENU(name)))); | |
148 account = g_object_get_data(G_OBJECT(item), "account"); | |
149 | |
150 if (!account) { | |
151 gaim_notify_error(NULL, NULL, _("Please create an account."), NULL); | |
152 return; | |
153 } | |
154 | |
155 gaim_account_set_password(account, (*password != '\0') ? password : NULL); | |
156 | |
157 gaim_account_connect(account); | |
158 } | |
159 | |
160 /* <name> is a comma-separated list of names, or NULL | |
161 if NULL and there is at least one user defined in .gaimrc, try to login. | |
162 if not NULL, parse <name> into separate strings, look up each one in | |
163 .gaimrc and, if it's there, try to login. | |
164 returns: 0 if successful | |
165 -1 if no user was found that had a saved password | |
166 */ | |
167 static int dologin_named(char *name) | |
168 { | |
169 GaimAccount *account; | |
170 char **names, **n; | |
171 int retval = -1; | |
172 | |
173 if (name !=NULL) { /* list of names given */ | |
174 names = g_strsplit(name, ",", 32); | |
175 for (n = names; *n != NULL; n++) { | |
176 account = gaim_accounts_find(*n, NULL); | |
177 if (account) { /* found a user */ | |
178 retval = 0; | |
179 gaim_account_connect(account); | |
180 } | |
181 } | |
182 g_strfreev(names); | |
183 } else { /* no name given, use default */ | |
184 account = (GaimAccount *)gaim_accounts_get_all()->data; | |
185 retval = 0; | |
186 gaim_account_connect(account); | |
187 } | |
188 | |
189 return retval; | |
190 } | |
191 | |
192 | |
193 static void combo_changed(GtkWidget *menu, GaimAccount *account, gpointer data) | |
194 { | |
195 if (account && gaim_account_get_remember_password(account)) { | |
196 gtk_entry_set_text(GTK_ENTRY(pass), account->password); | |
197 } else { | |
198 gtk_entry_set_text(GTK_ENTRY(pass), ""); | |
199 } | |
200 } | |
201 | |
202 | |
203 static void login_window_closed(GtkWidget *w, GdkEvent *ev, gpointer d) | |
204 { | |
205 if(docklet_count) { | |
206 #ifdef _WIN32 | |
207 wgaim_systray_minimize(mainwindow); | |
208 #endif | |
209 gtk_widget_hide(mainwindow); | |
210 } else | |
211 gaim_core_quit(); | |
212 } | |
213 | |
214 void show_login() | |
215 { | |
216 GtkWidget *image; | |
217 GtkWidget *vbox; | |
218 GtkWidget *button; | |
219 GtkWidget *hbox; | |
220 GtkWidget *label; | |
221 GtkWidget *vbox2; | |
222 | |
223 /* Do we already have a main window opened? If so, bring it back, baby... ribs... yeah */ | |
224 if (mainwindow) { | |
225 gtk_window_present(GTK_WINDOW(mainwindow)); | |
226 return; | |
227 } | |
228 | |
229 mainwindow = gtk_window_new(GTK_WINDOW_TOPLEVEL); | |
230 | |
231 gtk_window_set_role(GTK_WINDOW(mainwindow), "login"); | |
232 gtk_window_set_resizable(GTK_WINDOW(mainwindow), FALSE); | |
233 gtk_window_set_title(GTK_WINDOW(mainwindow), _("Login")); | |
234 gtk_container_set_border_width(GTK_CONTAINER(mainwindow), 5); | |
235 g_signal_connect(G_OBJECT(mainwindow), "delete_event", | |
236 G_CALLBACK(login_window_closed), mainwindow); | |
237 | |
238 vbox = gtk_vbox_new(FALSE, 0); | |
239 gtk_container_add(GTK_CONTAINER(mainwindow), vbox); | |
240 | |
241 image = gtk_image_new_from_stock(GAIM_STOCK_LOGO, gtk_icon_size_from_name(GAIM_ICON_SIZE_LOGO)); | |
242 gtk_box_pack_start(GTK_BOX(vbox), image, FALSE, FALSE, 0); | |
243 | |
244 vbox2 = gtk_vbox_new(FALSE, 0); | |
245 gtk_container_set_border_width(GTK_CONTAINER(vbox2), 5); | |
246 | |
247 /* why isn't there a gtk_label_new_with_markup? */ | |
248 label = gtk_label_new(NULL); | |
249 gtk_label_set_markup_with_mnemonic(GTK_LABEL(label), _("<b>_Account:</b>")); | |
250 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); | |
251 gtk_box_pack_start(GTK_BOX(vbox2), label, FALSE, FALSE, 0); | |
252 | |
253 name = gaim_gtk_account_option_menu_new(NULL, TRUE, G_CALLBACK(combo_changed), NULL, NULL); | |
254 gtk_label_set_mnemonic_widget(GTK_LABEL(label), name); | |
255 | |
256 gtk_box_pack_start(GTK_BOX(vbox2), name, FALSE, TRUE, 0); | |
257 gtk_box_pack_start(GTK_BOX(vbox), vbox2, FALSE, TRUE, 0); | |
258 | |
259 vbox2 = gtk_vbox_new(FALSE, 0); | |
260 gtk_container_set_border_width(GTK_CONTAINER(vbox2), 5); | |
261 | |
262 label = gtk_label_new(NULL); | |
263 gtk_label_set_markup_with_mnemonic(GTK_LABEL(label), _("<b>_Password:</b>")); | |
264 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); | |
265 gtk_box_pack_start(GTK_BOX(vbox2), label, FALSE, FALSE, 0); | |
266 | |
267 pass = gtk_entry_new(); | |
268 gtk_label_set_mnemonic_widget(GTK_LABEL(label), pass); | |
269 gtk_entry_set_visibility(GTK_ENTRY(pass), FALSE); | |
270 g_signal_connect(G_OBJECT(pass), "activate", | |
271 G_CALLBACK(dologin), mainwindow); | |
272 gtk_box_pack_start(GTK_BOX(vbox2), pass, FALSE, TRUE, 0); | |
273 gtk_box_pack_start(GTK_BOX(vbox), vbox2, FALSE, TRUE, 0); | |
274 | |
275 /* Now for the button box */ | |
276 hbox = gtk_hbox_new(TRUE, 0); | |
277 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 5); | |
278 | |
279 /* And now for the buttons */ | |
280 button = gaim_pixbuf_button_from_stock(_("A_ccounts"), GAIM_STOCK_ACCOUNTS, GAIM_BUTTON_VERTICAL); | |
281 gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE); | |
282 g_signal_connect(G_OBJECT(button), "clicked", | |
283 G_CALLBACK(gaim_gtk_accounts_window_show), mainwindow); | |
284 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0); | |
285 | |
286 button = gaim_pixbuf_button_from_stock(_("P_references"), GTK_STOCK_PREFERENCES, GAIM_BUTTON_VERTICAL); | |
287 gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE); | |
288 g_signal_connect(G_OBJECT(button), "clicked", | |
289 G_CALLBACK(gaim_gtk_prefs_show), mainwindow); | |
290 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0); | |
291 | |
292 button = gaim_pixbuf_button_from_stock(_("_Log in"), GAIM_STOCK_SIGN_ON, GAIM_BUTTON_VERTICAL); | |
293 gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE); | |
294 g_signal_connect(G_OBJECT(button), "clicked", | |
295 G_CALLBACK(dologin), mainwindow); | |
296 g_signal_connect(G_OBJECT(button), "button-press-event", G_CALLBACK(domiddleclick), NULL); | |
297 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0); | |
298 | |
299 /* Now grab the focus that we need */ | |
300 if (gaim_accounts_get_all()) { | |
301 GaimAccount *account = gaim_accounts_get_all()->data; | |
302 | |
303 if (gaim_account_get_remember_password(account)) { | |
304 combo_changed(NULL, account, NULL); | |
305 gtk_widget_grab_focus(button); | |
306 } else { | |
307 gtk_widget_grab_focus(pass); | |
308 } | |
309 } else { | |
310 gaim_gtk_accounts_window_show(); | |
311 gtk_widget_grab_focus(button); | |
312 } | |
313 | |
314 /* And raise the curtain! */ | |
315 gtk_widget_show_all(mainwindow); | |
316 | |
317 /* XXX - TODO - STATUS - Remove this! */ | |
318 gaim_gtk_status_window_show(); | |
319 } | |
320 | |
321 static void | |
322 clean_pid(void) | |
323 { | |
324 #ifndef _WIN32 | |
325 int status; | |
326 pid_t pid; | |
327 | |
328 do { | |
329 pid = waitpid(-1, &status, WNOHANG); | |
330 } while (pid != 0 && pid != (pid_t)-1); | |
331 if(pid == (pid_t)-1 && errno != ECHILD) { | |
332 char errmsg[BUFSIZ]; | |
333 snprintf(errmsg, BUFSIZ, "Warning: waitpid() returned %d", pid); | |
334 perror(errmsg); | |
335 } | |
336 #endif | |
337 } | |
338 | |
339 #if HAVE_SIGNAL_H | |
340 void sighandler(int sig) | |
341 { | |
342 switch (sig) { | |
343 case SIGHUP: | |
344 gaim_debug(GAIM_DEBUG_WARNING, "sighandler", | |
345 "Caught signal %d\n", sig); | |
346 gaim_connections_disconnect_all(); | |
347 break; | |
348 case SIGSEGV: | |
349 #ifndef DEBUG | |
350 fprintf(stderr, "Gaim has segfaulted and attempted to dump a core file.\n" | |
351 "This is a bug in the software and has happened through\n" | |
352 "no fault of your own.\n\n" | |
353 "It is possible that this bug is already fixed in CVS.\n" | |
354 "If you can reproduce the crash, please notify the gaim\n" | |
355 "maintainers by reporting a bug at\n" | |
356 GAIM_WEBSITE "bug.php\n\n" | |
357 "Please make sure to specify what you were doing at the time,\n" | |
358 "and post the backtrace from the core file. If you do not know\n" | |
359 "how to get the backtrace, please get instructions at\n" | |
360 GAIM_WEBSITE "gdb.php. If you need further\n" | |
361 "assistance, please IM either RobFlynn or SeanEgn and\n" | |
362 "they can help you.\n"); | |
363 #else | |
364 fprintf(stderr, "Hi, user. We need to talk.\n" | |
365 "I think something's gone wrong here. It's probably my fault.\n" | |
366 "No, really, it's not you... it's me... no no no, I think we get along well\n" | |
367 "it's just that.... well, I want to see other people. I... what?!? NO! I haven't\n" | |
368 "been cheating on you!! How many times do you want me to tell you?! And for the\n" | |
369 "last time, it's just a rash!\n"); | |
370 /*g_on_error_query (g_get_prgname());*/ | |
371 #endif | |
372 abort(); | |
373 break; | |
374 case SIGCHLD: | |
375 clean_pid(); | |
376 #if HAVE_SIGNAL_H | |
377 signal(SIGCHLD, sighandler); /* restore signal catching on this one! */ | |
378 #endif | |
379 break; | |
380 default: | |
381 gaim_debug(GAIM_DEBUG_WARNING, "sighandler", | |
382 "Caught signal %d\n", sig); | |
383 gaim_connections_disconnect_all(); | |
384 | |
385 gaim_plugins_unload_all(); | |
386 | |
387 if (gtk_main_level()) | |
388 gtk_main_quit(); | |
389 exit(0); | |
390 } | |
391 } | |
392 #endif | |
393 | |
394 static int ui_main() | |
395 { | |
396 #ifndef _WIN32 | |
397 GList *icons = NULL; | |
398 GdkPixbuf *icon = NULL; | |
399 char *icon_path; | |
400 #endif | |
401 | |
402 if (current_smiley_theme == NULL) { | |
403 smiley_theme_probe(); | |
404 if (smiley_themes) { | |
405 struct smiley_theme *smile = smiley_themes->data; | |
406 load_smiley_theme(smile->path, TRUE); | |
407 } | |
408 } | |
409 | |
410 gaim_gtk_blist_setup_sort_methods(); | |
411 | |
412 #ifndef _WIN32 | |
413 /* use the nice PNG icon for all the windows */ | |
414 icon_path = g_build_filename(DATADIR, "pixmaps", "gaim", "icons", "online.png", NULL); | |
415 icon = gdk_pixbuf_new_from_file(icon_path, NULL); | |
416 g_free(icon_path); | |
417 if (icon) { | |
418 icons = g_list_append(icons,icon); | |
419 gtk_window_set_default_icon_list(icons); | |
420 g_object_unref(G_OBJECT(icon)); | |
421 g_list_free(icons); | |
422 } else { | |
423 gaim_debug(GAIM_DEBUG_ERROR, "ui_main", | |
424 "Failed to load the default window icon!\n"); | |
425 } | |
426 #endif | |
427 | |
428 return 0; | |
429 } | |
430 | |
431 static void set_first_user(const char *name) | |
432 { | |
433 GaimAccount *account; | |
434 | |
435 account = gaim_accounts_find(name, NULL); | |
436 | |
437 /* Place it as the first user. */ | |
438 if (account != NULL) | |
439 gaim_accounts_reorder(account, 0); | |
440 } | |
441 | |
442 static void | |
443 debug_init(void) | |
444 { | |
445 gaim_debug_set_ui_ops(gaim_gtk_debug_get_ui_ops()); | |
446 gaim_gtk_debug_init(); | |
447 } | |
448 | |
449 static void | |
450 gaim_gtk_ui_init(void) | |
451 { | |
452 /* Set the UI operation structures. */ | |
453 gaim_accounts_set_ui_ops(gaim_gtk_accounts_get_ui_ops()); | |
454 gaim_conversations_set_win_ui_ops(gaim_gtk_conversations_get_win_ui_ops()); | |
455 gaim_xfers_set_ui_ops(gaim_gtk_xfers_get_ui_ops()); | |
456 gaim_blist_set_ui_ops(gaim_gtk_blist_get_ui_ops()); | |
457 gaim_notify_set_ui_ops(gaim_gtk_notify_get_ui_ops()); | |
458 gaim_privacy_set_ui_ops(gaim_gtk_privacy_get_ui_ops()); | |
459 gaim_request_set_ui_ops(gaim_gtk_request_get_ui_ops()); | |
460 gaim_sound_set_ui_ops(gaim_gtk_sound_get_ui_ops()); | |
461 gaim_connections_set_ui_ops(gaim_gtk_connections_get_ui_ops()); | |
462 | |
463 gaim_gtk_stock_init(); | |
464 gaim_gtk_prefs_init(); | |
465 gaim_gtk_account_init(); | |
466 gaim_gtk_blist_init(); | |
467 gaim_gtk_conversations_init(); | |
468 gaim_gtk_pounces_init(); | |
469 gaim_gtk_privacy_init(); | |
470 gaim_gtk_status_init(); | |
471 gaim_gtk_xfers_init(); | |
472 gaim_gtk_roomlist_init(); | |
473 } | |
474 | |
475 static void | |
476 gaim_gtk_quit(void) | |
477 { | |
478 /* XXX? */ | |
479 /* YYY is there an XXX here? */ | |
480 | |
481 /* captain's log, stardate... */ | |
482 /* LOG system_log(log_quit, NULL, NULL, OPT_LOG_BUDDY_SIGNON | OPT_LOG_MY_SIGNON); */ | |
483 | |
484 #ifdef USE_SM | |
485 /* unplug */ | |
486 session_end(); | |
487 #endif | |
488 | |
489 /* Save the plugins we have loaded for next time. */ | |
490 gaim_gtk_plugins_save(); | |
491 | |
492 /* and end it all... */ | |
493 gtk_main_quit(); | |
494 } | |
495 | |
496 static GaimCoreUiOps core_ops = | |
497 { | |
498 gaim_gtk_prefs_init, | |
499 debug_init, | |
500 gaim_gtk_ui_init, | |
501 gaim_gtk_quit | |
502 }; | |
503 | |
504 static GaimCoreUiOps * | |
505 gaim_gtk_core_get_ui_ops(void) | |
506 { | |
507 return &core_ops; | |
508 } | |
509 | |
510 static void | |
511 show_usage(int mode, const char *name) | |
512 { | |
513 char *text=NULL; | |
514 | |
515 switch (mode) { | |
516 case 0: /* full help text */ | |
517 text=g_strdup_printf(_("Gaim %s\n" | |
518 "Usage: %s [OPTION]...\n\n" | |
519 " -a, --acct display account editor window\n" | |
520 " -w, --away[=MESG] make away on signon (optional argument MESG specifies\n" | |
521 " name of away message to use)\n" | |
522 " -l, --login[=NAME] automatically login (optional argument NAME specifies\n" | |
523 " account(s) to use, seperated by commas)\n" | |
524 " -n, --loginwin don't automatically login; show login window\n" | |
525 " -u, --user=NAME use account NAME\n" | |
526 " -c, --config=DIR use DIR for config files\n" | |
527 " -d, --debug print debugging messages to stdout\n" | |
528 " -v, --version display the current version and exit\n" | |
529 " -h, --help display this help and exit\n"), VERSION, name); | |
530 break; | |
531 case 1: /* short message */ | |
532 text=g_strdup_printf(_("Gaim %s. Try `%s -h' for more information.\n"), VERSION, name); | |
533 break; | |
534 } | |
535 | |
536 if(text) { | |
537 char *text_conv; | |
538 GError *error=NULL; | |
539 | |
540 /* tries to convert 'text' to users locale */ | |
541 text_conv=g_locale_from_utf8(text,-1,NULL,NULL,&error); | |
542 if(text_conv) { | |
543 puts(text_conv); | |
544 g_free(text_conv); | |
545 } | |
546 /* use 'text' as a fallback */ | |
547 else { | |
548 g_warning("%s\n", error->message); | |
549 g_error_free(error); | |
550 puts(text); | |
551 } | |
552 g_free(text); | |
553 } | |
554 } | |
555 | |
556 #ifdef HAVE_STARTUP_NOTIFICATION | |
557 static void | |
558 sn_error_trap_push(SnDisplay *display, Display *xdisplay) | |
559 { | |
560 gdk_error_trap_push(); | |
561 } | |
562 | |
563 static void | |
564 sn_error_trap_pop(SnDisplay *display, Display *xdisplay) | |
565 { | |
566 gdk_error_trap_pop(); | |
567 } | |
568 | |
569 static void | |
570 startup_notification_complete(void) | |
571 { | |
572 Display *xdisplay; | |
573 | |
574 xdisplay = GDK_DISPLAY(); | |
575 sn_display = sn_display_new(xdisplay, | |
576 sn_error_trap_push, | |
577 sn_error_trap_pop); | |
578 sn_context = | |
579 sn_launchee_context_new_from_environment(sn_display, | |
580 DefaultScreen(xdisplay)); | |
581 | |
582 if (sn_context != NULL) | |
583 { | |
584 sn_launchee_context_complete(sn_context); | |
585 sn_launchee_context_unref(sn_context); | |
586 | |
587 sn_display_unref(sn_display); | |
588 } | |
589 } | |
590 #endif /* HAVE_STARTUP_NOTIFICATION */ | |
591 | |
592 #ifndef _WIN32 | |
593 static char *gaim_find_binary_location(void *symbol, void *data) | |
594 { | |
595 static char *fullname = NULL; | |
596 static gboolean first = TRUE; | |
597 | |
598 char *argv0 = data; | |
599 struct stat st; | |
600 char *basebuf, *linkbuf, *fullbuf; | |
601 | |
602 if (!first) | |
603 /* We've already been through this. */ | |
604 return strdup(fullname); | |
605 | |
606 first = FALSE; | |
607 | |
608 if (!argv0) | |
609 return NULL; | |
610 | |
611 | |
612 basebuf = g_find_program_in_path(argv0); | |
613 | |
614 /* But we still need to deal with symbolic links */ | |
615 lstat(basebuf, &st); | |
616 while ((st.st_mode & S_IFLNK) == S_IFLNK) { | |
617 linkbuf = g_malloc(1024); | |
618 readlink(basebuf, linkbuf, 1024); | |
619 if (linkbuf[0] == G_DIR_SEPARATOR) { | |
620 /* an absolute path */ | |
621 fullbuf = g_strdup(linkbuf); | |
622 } else { | |
623 char *dirbuf = g_path_get_dirname(basebuf); | |
624 /* a relative path */ | |
625 fullbuf = g_strdup_printf("%s%s%s", | |
626 dirbuf, G_DIR_SEPARATOR_S, | |
627 linkbuf); | |
628 g_free(dirbuf); | |
629 } | |
630 /* There's no memory leak here. Really! */ | |
631 g_free(linkbuf); | |
632 g_free(basebuf); | |
633 basebuf = fullbuf; | |
634 lstat(basebuf, &st); | |
635 } | |
636 | |
637 fullname = basebuf; | |
638 return strdup(fullname); | |
639 } | |
640 #endif /* #ifndef _WIN32 */ | |
641 | |
642 /* FUCKING GET ME A TOWEL! */ | |
643 #ifdef _WIN32 | |
644 int gaim_main(HINSTANCE hint, int argc, char *argv[]) | |
645 #else | |
646 int main(int argc, char *argv[]) | |
647 #endif | |
648 { | |
649 int opt_acct = 0, opt_help = 0, opt_version = 0, opt_login = 0, opt_nologin = 0, dologin_ret = -1; | |
650 char *opt_user_arg = NULL, *opt_login_arg = NULL; | |
651 char *opt_session_arg = NULL, *opt_config_dir_arg = NULL; | |
652 char *plugin_search_paths[3]; | |
653 #if HAVE_SIGNAL_H | |
654 int sig_indx; /* for setting up signal catching */ | |
655 sigset_t sigset; | |
656 void (*prev_sig_disp)(); | |
657 #endif | |
658 int opt, opt_user = 0; | |
659 int i; | |
660 gboolean gui_check; | |
661 gchar *gaimrc, *accountsxml; | |
662 | |
663 struct option long_options[] = { | |
664 {"acct", no_argument, NULL, 'a'}, | |
665 /*{"away", optional_argument, NULL, 'w'}, */ | |
666 {"help", no_argument, NULL, 'h'}, | |
667 /*{"login", optional_argument, NULL, 'l'}, */ | |
668 {"loginwin", no_argument, NULL, 'n'}, | |
669 {"user", required_argument, NULL, 'u'}, | |
670 {"config", required_argument, NULL, 'c'}, | |
671 {"debug", no_argument, NULL, 'd'}, | |
672 {"version", no_argument, NULL, 'v'}, | |
673 {"session", required_argument, NULL, 's'}, | |
674 {0, 0, 0, 0} | |
675 }; | |
676 | |
677 #ifdef DEBUG | |
678 opt_debug = 1; | |
679 #endif | |
680 #ifndef _WIN32 | |
681 br_set_locate_fallback_func(gaim_find_binary_location, argv[0]); | |
682 #endif | |
683 #ifdef ENABLE_NLS | |
684 bindtextdomain(PACKAGE, LOCALEDIR); | |
685 bind_textdomain_codeset(PACKAGE, "UTF-8"); | |
686 textdomain(PACKAGE); | |
687 #endif | |
688 | |
689 #if HAVE_SIGNAL_H | |
690 /* Let's not violate any PLA's!!!! */ | |
691 /* jseymour: whatever the fsck that means */ | |
692 /* Robot101: for some reason things like gdm like to block * | |
693 * useful signals like SIGCHLD, so we unblock all the ones we * | |
694 * declare a handler for. thanks JSeymour and Vann. */ | |
695 if (sigemptyset(&sigset)) { | |
696 char errmsg[BUFSIZ]; | |
697 snprintf(errmsg, BUFSIZ, "Warning: couldn't initialise empty signal set"); | |
698 perror(errmsg); | |
699 } | |
700 for(sig_indx = 0; catch_sig_list[sig_indx] != -1; ++sig_indx) { | |
701 if((prev_sig_disp = signal(catch_sig_list[sig_indx], sighandler)) == SIG_ERR) { | |
702 char errmsg[BUFSIZ]; | |
703 snprintf(errmsg, BUFSIZ, "Warning: couldn't set signal %d for catching", | |
704 catch_sig_list[sig_indx]); | |
705 perror(errmsg); | |
706 } | |
707 if(sigaddset(&sigset, catch_sig_list[sig_indx])) { | |
708 char errmsg[BUFSIZ]; | |
709 snprintf(errmsg, BUFSIZ, "Warning: couldn't include signal %d for unblocking", | |
710 catch_sig_list[sig_indx]); | |
711 perror(errmsg); | |
712 } | |
713 } | |
714 for(sig_indx = 0; ignore_sig_list[sig_indx] != -1; ++sig_indx) { | |
715 if((prev_sig_disp = signal(ignore_sig_list[sig_indx], SIG_IGN)) == SIG_ERR) { | |
716 char errmsg[BUFSIZ]; | |
717 snprintf(errmsg, BUFSIZ, "Warning: couldn't set signal %d to ignore", | |
718 ignore_sig_list[sig_indx]); | |
719 perror(errmsg); | |
720 } | |
721 } | |
722 | |
723 if (sigprocmask(SIG_UNBLOCK, &sigset, NULL)) { | |
724 char errmsg[BUFSIZ]; | |
725 snprintf(errmsg, BUFSIZ, "Warning: couldn't unblock signals"); | |
726 perror(errmsg); | |
727 } | |
728 #endif | |
729 | |
730 for (i = 0; i < argc; i++) { | |
731 /* --login option */ | |
732 if (strstr(argv[i], "--l") == argv[i]) { | |
733 char *equals; | |
734 opt_login = 1; | |
735 if ((equals = strchr(argv[i], '=')) != NULL) { | |
736 /* --login=NAME */ | |
737 opt_login_arg = g_strdup(equals + 1); | |
738 if (strlen(opt_login_arg) == 0) { | |
739 g_free(opt_login_arg); | |
740 opt_login_arg = NULL; | |
741 } | |
742 } else if (i + 1 < argc && argv[i + 1][0] != '-') { | |
743 /* --login NAME */ | |
744 opt_login_arg = g_strdup(argv[i + 1]); | |
745 strcpy(argv[i + 1], " "); | |
746 } | |
747 strcpy(argv[i], " "); | |
748 } | |
749 /* -l option */ | |
750 else if (strstr(argv[i], "-l") == argv[i]) { | |
751 opt_login = 1; | |
752 if (strlen(argv[i]) > 2) { | |
753 /* -lNAME */ | |
754 opt_login_arg = g_strdup(argv[i] + 2); | |
755 } else if (i + 1 < argc && argv[i + 1][0] != '-') { | |
756 /* -l NAME */ | |
757 opt_login_arg = g_strdup(argv[i + 1]); | |
758 strcpy(argv[i + 1], " "); | |
759 } | |
760 strcpy(argv[i], " "); | |
761 } | |
762 /* --away option */ | |
763 else if (strstr(argv[i], "--aw") == argv[i]) { | |
764 char *equals; | |
765 opt_away = 1; | |
766 if ((equals = strchr(argv[i], '=')) != NULL) { | |
767 /* --away=MESG */ | |
768 opt_away_arg = g_strdup(equals + 1); | |
769 if (strlen(opt_away_arg) == 0) { | |
770 g_free(opt_away_arg); | |
771 opt_away_arg = NULL; | |
772 } | |
773 } else if (i + 1 < argc && argv[i + 1][0] != '-') { | |
774 /* --away MESG */ | |
775 opt_away_arg = g_strdup(argv[i + 1]); | |
776 strcpy(argv[i + 1], " "); | |
777 } | |
778 strcpy(argv[i], " "); | |
779 } | |
780 /* -w option */ | |
781 else if (strstr(argv[i], "-w") == argv[i]) { | |
782 opt_away = 1; | |
783 if (strlen(argv[i]) > 2) { | |
784 /* -wMESG */ | |
785 opt_away_arg = g_strdup(argv[i] + 2); | |
786 } else if (i + 1 < argc && argv[i + 1][0] != '-') { | |
787 /* -w MESG */ | |
788 opt_away_arg = g_strdup(argv[i + 1]); | |
789 strcpy(argv[i + 1], " "); | |
790 } | |
791 strcpy(argv[i], " "); | |
792 } | |
793 } | |
794 /* | |
795 if (opt_login) { | |
796 printf ("--login given with arg %s\n", | |
797 opt_login_arg ? opt_login_arg : "NULL"); | |
798 exit(0); | |
799 } | |
800 */ | |
801 | |
802 gui_check = gtk_init_check(&argc, &argv); | |
803 | |
804 /* scan command-line options */ | |
805 opterr = 1; | |
806 while ((opt = getopt_long(argc, argv, | |
807 #ifndef _WIN32 | |
808 "adhu:c:vns:", | |
809 #else | |
810 "adhu:c:vn", | |
811 #endif | |
812 long_options, NULL)) != -1) { | |
813 switch (opt) { | |
814 case 'u': /* set user */ | |
815 opt_user = 1; | |
816 opt_user_arg = g_strdup(optarg); | |
817 break; | |
818 case 'a': /* account editor */ | |
819 opt_acct = 1; | |
820 break; | |
821 case 'd': /* debug */ | |
822 opt_debug = 1; | |
823 break; | |
824 case 'c': /* use specified config dir */ | |
825 set_gaim_user_dir(optarg); | |
826 opt_config_dir_arg = g_strdup(optarg); | |
827 break; | |
828 case 's': /* use existing session ID */ | |
829 opt_session_arg = g_strdup(optarg); | |
830 break; | |
831 case 'v': /* version */ | |
832 opt_version = 1; | |
833 break; | |
834 case 'h': /* help */ | |
835 opt_help = 1; | |
836 break; | |
837 case 'n': /* don't autologin */ | |
838 opt_nologin = 1; | |
839 break; | |
840 case '?': | |
841 default: | |
842 show_usage(1, argv[0]); | |
843 return 0; | |
844 break; | |
845 } | |
846 } | |
847 | |
848 /* show help message */ | |
849 if (opt_help) { | |
850 show_usage(0, argv[0]); | |
851 return 0; | |
852 } | |
853 /* show version message */ | |
854 if (opt_version) { | |
855 printf("Gaim %s\n",VERSION); | |
856 return 0; | |
857 } | |
858 | |
859 if (!gui_check) { | |
860 char *display = gdk_get_display(); | |
861 | |
862 g_warning("cannot open display: %s", display ? display : "unset"); | |
863 g_free(display); | |
864 | |
865 return 1; | |
866 } | |
867 | |
868 #ifdef _WIN32 | |
869 wgaim_init(hint); | |
870 #endif | |
871 gaim_core_set_ui_ops(gaim_gtk_core_get_ui_ops()); | |
872 gaim_eventloop_set_ui_ops(gaim_gtk_eventloop_get_ui_ops()); | |
873 | |
874 if (!gaim_core_init(GAIM_GTK_UI)) { | |
875 fprintf(stderr, | |
876 "Initialization of the Gaim core failed. Dumping core.\n" | |
877 "Please report this!\n"); | |
878 abort(); | |
879 } | |
880 | |
881 plugin_search_paths[0] = g_strdup(LIBDIR); | |
882 plugin_search_paths[1] = gaim_user_dir(); | |
883 plugin_search_paths[2] = g_build_filename(gaim_user_dir(), "plugins", NULL); | |
884 | |
885 gaim_plugins_set_search_paths(sizeof(plugin_search_paths) / | |
886 sizeof(*plugin_search_paths), | |
887 plugin_search_paths); | |
888 | |
889 g_free(plugin_search_paths[0]); | |
890 g_free(plugin_search_paths[2]); | |
891 | |
892 gaim_plugins_probe(NULL); | |
893 | |
894 /* XXX - Remove this check. Maybe in 2005. --KingAnt, 25 Jul 2004 */ | |
895 gaimrc = g_build_filename(gaim_home_dir(), ".gaimrc", NULL); | |
896 accountsxml = g_build_filename(gaim_user_dir(), "accounts.xml", NULL); | |
897 if (g_file_test(gaimrc, G_FILE_TEST_EXISTS) && | |
898 !g_file_test(accountsxml, G_FILE_TEST_EXISTS)) { | |
899 gaim_notify_error(NULL, NULL, _("Unable to load preferences"), _("Gaim was not able to load your preferences because they are stored in an old format that is no longer used. Please reconfigure your settings using the Preferences window.")); | |
900 } | |
901 g_free(gaimrc); | |
902 g_free(accountsxml); | |
903 | |
904 gaim_accounts_load(); | |
905 | |
906 gaim_set_blist(gaim_blist_new()); | |
907 gaim_blist_load(); | |
908 | |
909 gaim_prefs_load(); | |
910 | |
911 gaim_prefs_update_old(); | |
912 gaim_gtk_prefs_update_old(); | |
913 | |
914 /* load plugins we had when we quit */ | |
915 gaim_plugins_load_saved("/gaim/gtk/plugins/loaded"); | |
916 | |
917 gaim_pounces_load(); | |
918 gaim_statuses_load(); | |
919 | |
920 ui_main(); | |
921 | |
922 #ifdef USE_SM | |
923 session_init(argv[0], opt_session_arg, opt_config_dir_arg); | |
924 #endif | |
925 if (opt_session_arg != NULL) { | |
926 g_free(opt_session_arg); | |
927 opt_session_arg = NULL; | |
928 } | |
929 | |
930 if (opt_config_dir_arg != NULL) { | |
931 g_free(opt_config_dir_arg); | |
932 opt_config_dir_arg = NULL; | |
933 } | |
934 | |
935 /* set the default username */ | |
936 if (opt_user_arg != NULL) { | |
937 set_first_user(opt_user_arg); | |
938 g_free(opt_user_arg); | |
939 opt_user_arg = NULL; | |
940 } | |
941 | |
942 if (gaim_prefs_get_bool("/gaim/gtk/debug/enabled")) | |
943 gaim_gtk_debug_window_show(); | |
944 | |
945 /* deal with --login */ | |
946 if (opt_login) { | |
947 dologin_ret = dologin_named(opt_login_arg); | |
948 if (opt_login_arg != NULL) { | |
949 g_free(opt_login_arg); | |
950 opt_login_arg = NULL; | |
951 } | |
952 } | |
953 | |
954 if (!opt_acct && !opt_nologin) | |
955 gaim_accounts_auto_login(GAIM_GTK_UI); | |
956 | |
957 if (opt_acct) { | |
958 gaim_gtk_accounts_window_show(); | |
959 } else if ((dologin_ret == -1) && !gaim_connections_get_all()) | |
960 show_login(); | |
961 | |
962 #ifdef HAVE_STARTUP_NOTIFICATION | |
963 startup_notification_complete(); | |
964 #endif | |
965 gtk_main(); | |
966 gaim_sound_shutdown(); | |
967 #ifdef _WIN32 | |
968 wgaim_cleanup(); | |
969 #endif | |
970 | |
971 | |
972 return 0; | |
973 | |
974 } |