00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #ifdef HAVE_CONFIG_H
00027 # include "config.h"
00028 #endif
00029
00030 #include <gtk/gtk.h>
00031
00032 #include "main.h"
00033
00034 #include <glib/gprintf.h>
00035
00036 #include <libaudcore/audstrings.h>
00037 #include <libaudcore/hook.h>
00038 #include <libaudtag/audtag.h>
00039
00040 #ifdef USE_DBUS
00041 # include "dbus-service.h"
00042 # include "audctrl.h"
00043 #endif
00044
00045 #ifdef USE_EGGSM
00046 #include "eggsmclient.h"
00047 #include "eggdesktopfile.h"
00048 #endif
00049
00050 #include "audconfig.h"
00051 #include "chardet.h"
00052 #include "compatibility.h"
00053 #include "configdb.h"
00054 #include "debug.h"
00055 #include "drct.h"
00056 #include "equalizer.h"
00057 #include "i18n.h"
00058 #include "interface.h"
00059 #include "output.h"
00060 #include "playback.h"
00061 #include "playlist.h"
00062 #include "pluginenum.h"
00063 #include "signals.h"
00064 #include "util.h"
00065 #include "visualization.h"
00066
00067 #define AUTOSAVE_INTERVAL 300
00068
00069 static const gchar *application_name = N_("Audacious");
00070
00071 struct _AudCmdLineOpt
00072 {
00073 gchar **filenames;
00074 gint session;
00075 gboolean play, stop, pause, fwd, rew, play_pause, show_jump_box;
00076 gboolean enqueue, mainwin, remote, activate;
00077 gboolean enqueue_to_temp;
00078 gboolean version;
00079 gchar *previous_session_id;
00080 };
00081 typedef struct _AudCmdLineOpt AudCmdLineOpt;
00082
00083 static AudCmdLineOpt options;
00084
00085 gchar * aud_paths[BMP_PATH_COUNT];
00086
00087 #ifdef USE_DBUS
00088 MprisPlayer *mpris;
00089 MprisTrackList *mpris_tracklist;
00090 #endif
00091
00092 static void print_version(void)
00093 {
00094 g_printf("%s %s (%s)\n", _(application_name), VERSION, BUILDSTAMP);
00095 }
00096
00097 static void aud_make_user_dir(void)
00098 {
00099 const mode_t mode755 = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
00100
00101 make_directory(aud_paths[BMP_PATH_USER_DIR], mode755);
00102 make_directory(aud_paths[BMP_PATH_USER_PLUGIN_DIR], mode755);
00103 make_directory(aud_paths[BMP_PATH_USER_SKIN_DIR], mode755);
00104 make_directory(aud_paths[BMP_PATH_SKIN_THUMB_DIR], mode755);
00105 make_directory(aud_paths[BMP_PATH_PLAYLISTS_DIR], mode755);
00106 }
00107
00108 static void aud_free_paths(void)
00109 {
00110 gint i;
00111
00112 for (i = 0; i < BMP_PATH_COUNT; i++)
00113 {
00114 g_free(aud_paths[i]);
00115 aud_paths[i] = 0;
00116 }
00117 }
00118
00119 static void aud_init_paths()
00120 {
00121 gchar *xdg_config_home;
00122 gchar *xdg_data_home;
00123 gchar *xdg_cache_home;
00124
00125 xdg_config_home = (getenv ("XDG_CONFIG_HOME") == NULL) ? g_build_filename
00126 (getenv ("HOME"), ".config", NULL) : g_strdup (getenv ("XDG_CONFIG_HOME"));
00127 xdg_data_home = (getenv ("XDG_DATA_HOME") == NULL) ? g_build_filename
00128 (getenv ("HOME"), ".local", "share", NULL) : g_strdup (getenv
00129 ("XDG_DATA_HOME"));
00130 xdg_cache_home = (getenv ("XDG_CACHE_HOME") == NULL) ? g_build_filename
00131 (getenv ("HOME"), ".cache", NULL) : g_strdup (getenv ("XDG_CACHE_HOME"));
00132
00133 aud_paths[BMP_PATH_USER_DIR] = g_build_filename(xdg_config_home, "audacious", NULL);
00134 aud_paths[BMP_PATH_USER_SKIN_DIR] = g_build_filename(xdg_data_home, "audacious", "Skins", NULL);
00135 aud_paths[BMP_PATH_USER_PLUGIN_DIR] = g_build_filename(xdg_data_home, "audacious", "Plugins", NULL);
00136
00137 aud_paths[BMP_PATH_SKIN_THUMB_DIR] = g_build_filename(xdg_cache_home, "audacious", "thumbs", NULL);
00138
00139 aud_paths[BMP_PATH_PLAYLISTS_DIR] = g_build_filename(aud_paths[BMP_PATH_USER_DIR], "playlists", NULL);
00140
00141 aud_paths[BMP_PATH_CONFIG_FILE] = g_build_filename(aud_paths[BMP_PATH_USER_DIR], "config", NULL);
00142 aud_paths[BMP_PATH_PLAYLIST_FILE] = g_build_filename(aud_paths[BMP_PATH_USER_DIR], "playlist.xspf", NULL);
00143 aud_paths[BMP_PATH_ACCEL_FILE] = g_build_filename(aud_paths[BMP_PATH_USER_DIR], "accels", NULL);
00144
00145 aud_paths[BMP_PATH_GTKRC_FILE] = g_build_filename(aud_paths[BMP_PATH_USER_DIR], "gtkrc", NULL);
00146
00147 g_free(xdg_config_home);
00148 g_free(xdg_data_home);
00149 g_free(xdg_cache_home);
00150
00151 g_atexit(aud_free_paths);
00152 }
00153
00154 static GOptionEntry cmd_entries[] = {
00155 {"rew", 'r', 0, G_OPTION_ARG_NONE, &options.rew, N_("Skip backwards in playlist"), NULL},
00156 {"play", 'p', 0, G_OPTION_ARG_NONE, &options.play, N_("Start playing current playlist"), NULL},
00157 {"pause", 'u', 0, G_OPTION_ARG_NONE, &options.pause, N_("Pause current song"), NULL},
00158 {"stop", 's', 0, G_OPTION_ARG_NONE, &options.stop, N_("Stop current song"), NULL},
00159 {"play-pause", 't', 0, G_OPTION_ARG_NONE, &options.play_pause, N_("Pause if playing, play otherwise"), NULL},
00160 {"fwd", 'f', 0, G_OPTION_ARG_NONE, &options.fwd, N_("Skip forward in playlist"), NULL},
00161 {"show-jump-box", 'j', 0, G_OPTION_ARG_NONE, &options.show_jump_box, N_("Display Jump to File dialog"), NULL},
00162 {"enqueue", 'e', 0, G_OPTION_ARG_NONE, &options.enqueue, N_("Add files to the playlist"), NULL},
00163 {"enqueue-to-temp", 'E', 0, G_OPTION_ARG_NONE, &options.enqueue_to_temp, N_("Add new files to a temporary playlist"), NULL},
00164 {"show-main-window", 'm', 0, G_OPTION_ARG_NONE, &options.mainwin, N_("Display the main window"), NULL},
00165 {"activate", 'a', 0, G_OPTION_ARG_NONE, &options.activate, N_("Display all open Audacious windows"), NULL},
00166 {"version", 'v', 0, G_OPTION_ARG_NONE, &options.version, N_("Show version"), NULL},
00167 {"verbose", 'V', 0, G_OPTION_ARG_NONE, &cfg.verbose, N_("Print debugging messages"), NULL},
00168 {G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &options.filenames, N_("FILE..."), NULL},
00169 {NULL},
00170 };
00171
00172 static void parse_cmd_line_options(gint * argc, gchar *** argv)
00173 {
00174 GOptionContext *context;
00175 GError *error = NULL;
00176
00177 memset(&options, '\0', sizeof(AudCmdLineOpt));
00178 options.session = -1;
00179
00180 context = g_option_context_new(_("- play multimedia files"));
00181 g_option_context_add_main_entries(context, cmd_entries, PACKAGE_NAME);
00182 g_option_context_add_group(context, gtk_get_option_group(FALSE));
00183 #ifdef USE_EGGSM
00184 g_option_context_add_group(context, egg_sm_client_get_option_group());
00185 #endif
00186
00187 if (!g_option_context_parse(context, argc, argv, &error))
00188
00189 if (error->message && !g_strrstr(error->message, "-psn_0_"))
00190 {
00191 g_printerr(_("%s: %s\nTry `%s --help' for more information.\n"), (*argv)[0], error->message, (*argv)[0]);
00192 exit(EXIT_FAILURE);
00193 }
00194
00195 g_option_context_free (context);
00196 }
00197
00198 static void handle_cmd_line_filenames(gboolean is_running)
00199 {
00200 gint i;
00201 gchar *working, **filenames = options.filenames;
00202 GList * fns = NULL;
00203 #ifdef USE_DBUS
00204 DBusGProxy *session = audacious_get_dbus_proxy();
00205 #endif
00206
00207 if (filenames == NULL)
00208 return;
00209
00210 working = g_get_current_dir();
00211 for (i = 0; filenames[i] != NULL; i++)
00212 {
00213 gchar * uri;
00214
00215 if (strstr (filenames[i], "://"))
00216 uri = g_strdup (filenames[i]);
00217 else if (g_path_is_absolute (filenames[i]))
00218 uri = filename_to_uri (filenames[i]);
00219 else
00220 {
00221 gchar * absolute = g_build_filename (working, filenames[i], NULL);
00222 uri = filename_to_uri (absolute);
00223 g_free (absolute);
00224 }
00225
00226 fns = g_list_prepend(fns, uri);
00227 }
00228 fns = g_list_reverse(fns);
00229 g_free(working);
00230
00231 #ifdef USE_DBUS
00232 if (is_running)
00233 {
00234 if (options.enqueue_to_temp)
00235 audacious_remote_playlist_open_list_to_temp (session, fns);
00236 else if (options.enqueue)
00237 audacious_remote_playlist_add (session, fns);
00238 else
00239 audacious_remote_playlist_open_list (session, fns);
00240 }
00241 else
00242 #endif
00243 {
00244 if (options.enqueue_to_temp)
00245 {
00246 drct_pl_open_temp_list (fns);
00247 cfg.resume_state = 0;
00248 }
00249 else if (options.enqueue)
00250 drct_pl_add_list (fns, -1);
00251 else
00252 {
00253 drct_pl_open_list (fns);
00254 cfg.resume_state = 0;
00255 }
00256 }
00257
00258 g_list_foreach(fns, (GFunc) g_free, NULL);
00259 g_list_free(fns);
00260 }
00261
00262 static void handle_cmd_line_options_first(void)
00263 {
00264 #ifdef USE_DBUS
00265 DBusGProxy *session;
00266 #endif
00267
00268 if (options.version)
00269 {
00270 print_version();
00271 exit(EXIT_SUCCESS);
00272 }
00273
00274 #ifdef USE_DBUS
00275 session = audacious_get_dbus_proxy();
00276 if (audacious_remote_is_running(session))
00277 {
00278 handle_cmd_line_filenames(TRUE);
00279 if (options.rew)
00280 audacious_remote_playlist_prev(session);
00281 if (options.play)
00282 audacious_remote_play(session);
00283 if (options.pause)
00284 audacious_remote_pause(session);
00285 if (options.stop)
00286 audacious_remote_stop(session);
00287 if (options.fwd)
00288 audacious_remote_playlist_next(session);
00289 if (options.play_pause)
00290 audacious_remote_play_pause(session);
00291 if (options.show_jump_box)
00292 audacious_remote_show_jtf_box(session);
00293 if (options.mainwin)
00294 audacious_remote_main_win_toggle(session, 1);
00295 if (options.activate)
00296 audacious_remote_activate(session);
00297 exit(EXIT_SUCCESS);
00298 }
00299 #endif
00300 }
00301
00302 static void handle_cmd_line_options(void)
00303 {
00304 handle_cmd_line_filenames(FALSE);
00305
00306 if (cfg.resume_playback_on_startup && cfg.resume_state > 0)
00307 playback_play (cfg.resume_playback_on_startup_time, cfg.resume_state ==
00308 2);
00309
00310 if (options.play || options.play_pause)
00311 {
00312 if (! playback_get_playing ())
00313 playback_play (0, FALSE);
00314 else if (playback_get_paused ())
00315 playback_pause ();
00316 }
00317
00318 if (options.show_jump_box)
00319 interface_show_jump_to_track ();
00320 if (options.mainwin)
00321 interface_toggle_visibility ();
00322 }
00323
00324 void aud_quit (void)
00325 {
00326 AUDDBG ("Ending main loop.\n");
00327 gtk_main_quit ();
00328 }
00329
00330 static void shut_down (void)
00331 {
00332 AUDDBG ("Saving configuration.\n");
00333 aud_config_save();
00334 save_playlists ();
00335
00336 if (playback_get_playing ())
00337 playback_stop ();
00338
00339 AUDDBG ("Shutting down user interface subsystem.\n");
00340 interface_unload ();
00341
00342 output_cleanup ();
00343
00344 AUDDBG ("Plugin subsystem shutdown.\n");
00345 plugin_system_cleanup();
00346
00347 cfg_db_flush ();
00348
00349 AUDDBG ("Playlist cleanup.\n");
00350 playlist_end();
00351 }
00352
00353 #ifdef USE_DBUS
00354 static void mpris_status_cb1(gpointer hook_data, gpointer user_data)
00355 {
00356 mpris_emit_status_change(mpris, GPOINTER_TO_INT(user_data));
00357 }
00358
00359 static void mpris_status_cb2(gpointer hook_data, gpointer user_data)
00360 {
00361 mpris_emit_status_change(mpris, -1);
00362 }
00363
00364 void init_playback_hooks(void)
00365 {
00366 hook_associate("playback begin", mpris_status_cb1, GINT_TO_POINTER(MPRIS_STATUS_PLAY));
00367 hook_associate("playback pause", mpris_status_cb1, GINT_TO_POINTER(MPRIS_STATUS_PAUSE));
00368 hook_associate("playback unpause", mpris_status_cb1, GINT_TO_POINTER(MPRIS_STATUS_PLAY));
00369 hook_associate("playback stop", mpris_status_cb1, GINT_TO_POINTER(MPRIS_STATUS_STOP));
00370
00371 hook_associate("playback shuffle", mpris_status_cb2, NULL);
00372 hook_associate("playback repeat", mpris_status_cb2, NULL);
00373 hook_associate("playback no playlist advance", mpris_status_cb2, NULL);
00374 }
00375 #endif
00376
00377 static gboolean autosave_cb (void * unused)
00378 {
00379 AUDDBG ("Saving configuration.\n");
00380 aud_config_save ();
00381 cfg_db_flush ();
00382 save_playlists ();
00383 return TRUE;
00384 }
00385
00386 static PluginHandle * current_iface = NULL;
00387
00388 PluginHandle * iface_plugin_get_active (void)
00389 {
00390 return current_iface;
00391 }
00392
00393 void iface_plugin_set_active (PluginHandle * plugin)
00394 {
00395 AUDDBG ("Unloading visualizers.\n");
00396 vis_cleanup ();
00397
00398 AUDDBG ("Unloading %s.\n", plugin_get_name (current_iface));
00399 interface_unload ();
00400
00401 current_iface = plugin;
00402 interface_set_default (plugin);
00403
00404 AUDDBG ("Starting %s.\n", plugin_get_name (plugin));
00405 if (! interface_load (plugin))
00406 {
00407 fprintf (stderr, "%s failed to start.\n", plugin_get_name (plugin));
00408 exit (EXIT_FAILURE);
00409 }
00410
00411 AUDDBG ("Loading visualizers.\n");
00412 vis_init ();
00413 }
00414
00415 gint main(gint argc, gchar ** argv)
00416 {
00417
00418
00419 g_thread_init(NULL);
00420 if (!g_thread_supported())
00421 {
00422 g_printerr(_("Sorry, threads aren't supported on your platform.\n"));
00423 exit(EXIT_FAILURE);
00424 }
00425
00426 gdk_threads_init();
00427 mowgli_init();
00428 chardet_init();
00429 tag_init();
00430
00431 hook_init();
00432 hook_associate ("quit", (HookFunction) gtk_main_quit, NULL);
00433
00434
00435 gtk_set_locale();
00436 bindtextdomain(PACKAGE_NAME, LOCALEDIR);
00437 bind_textdomain_codeset(PACKAGE_NAME, "UTF-8");
00438 bindtextdomain(PACKAGE_NAME "-plugins", LOCALEDIR);
00439 bind_textdomain_codeset(PACKAGE_NAME "-plugins", "UTF-8");
00440 textdomain(PACKAGE_NAME);
00441
00442 #if !defined(_WIN32) && defined(USE_EGGSM)
00443 egg_set_desktop_file(AUDACIOUS_DESKTOP_FILE);
00444 #endif
00445 aud_init_paths();
00446 aud_make_user_dir();
00447
00448 gtk_rc_add_default_file(aud_paths[BMP_PATH_GTKRC_FILE]);
00449
00450 parse_cmd_line_options(&argc, &argv);
00451
00452 if (!gtk_init_check(&argc, &argv))
00453 {
00454
00455
00456
00457 g_printerr(_("%s: Unable to open display, exiting.\n"), argv[0]);
00458 exit(EXIT_FAILURE);
00459 }
00460
00461 AUDDBG ("Loading configuration.\n");
00462 aud_config_load();
00463 atexit (aud_config_free);
00464
00465 AUDDBG ("Initializing signal handlers.\n");
00466 signal_handlers_init();
00467
00468 AUDDBG ("Handling commandline options, part #1.\n");
00469 handle_cmd_line_options_first();
00470
00471 output_init ();
00472
00473 #ifdef USE_DBUS
00474 AUDDBG ("Initializing D-Bus.\n");
00475 init_dbus();
00476 init_playback_hooks();
00477 #endif
00478
00479 AUDDBG ("Initializing plugin subsystems.\n");
00480 plugin_system_init();
00481
00482 playlist_init ();
00483 load_playlists ();
00484 eq_init ();
00485
00486 AUDDBG ("Handling commandline options, part #2.\n");
00487 handle_cmd_line_options();
00488
00489 AUDDBG ("Registering interface hooks.\n");
00490 register_interface_hooks();
00491
00492 g_timeout_add_seconds (AUTOSAVE_INTERVAL, autosave_cb, NULL);
00493
00494 if ((current_iface = interface_get_default ()) == NULL)
00495 {
00496 fprintf (stderr, "No interface plugin found.\n");
00497 return EXIT_FAILURE;
00498 }
00499
00500 AUDDBG ("Starting %s.\n", plugin_get_name (current_iface));
00501 if (! interface_load (current_iface))
00502 {
00503 fprintf (stderr, "%s failed to start.\n", plugin_get_name (current_iface));
00504 return EXIT_FAILURE;
00505 }
00506
00507 AUDDBG ("Loading visualizers.\n");
00508 vis_init ();
00509
00510 AUDDBG ("Starting main loop.\n");
00511 gtk_main ();
00512
00513 AUDDBG ("Unloading visualizers.\n");
00514 vis_cleanup ();
00515
00516 AUDDBG ("Shutting down.\n");
00517 shut_down ();
00518 return EXIT_SUCCESS;
00519 }