2006-12-14 Francisco Javier F. Serrador <serrador@openshine.com>
[rhythmbox.git] / shell / main.c
blob60a48081e4bf64917d26e7e8621ff956f837ba88
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
3 * arch-tag: The Rhythmbox main entrypoint
5 * Copyright (C) 2002 Jorn Baayen
6 * Copyright (C) 2003,2004 Colin Walters <walters@gnome.org>
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, or (at your option)
11 * any later version.
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.
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include <config.h>
26 #include <stdlib.h>
27 #include <unistd.h>
28 #include <time.h>
29 #include <string.h>
30 #include <libintl.h>
31 #include <locale.h>
33 #include <glib/gi18n.h>
34 #include <gdk/gdkx.h> /* For _get_user_time... */
35 #include <gtk/gtk.h>
36 #include <glade/glade-init.h>
37 #include <libgnome/gnome-program.h>
38 #include <libgnomeui/gnome-ui-init.h>
39 #include <libgnomeui/gnome-app-helper.h>
40 #include <libgnomeui/gnome-authentication-manager.h>
42 #ifdef HAVE_GSTREAMER
43 #include <gst/gst.h>
44 #ifdef HAVE_GSTREAMER_0_8
45 #include <gst/gconf/gconf.h>
46 #include <gst/control/control.h>
47 #endif
48 #endif
49 #ifdef WITH_RHYTHMDB_GDA
50 #include <libgda/libgda.h>
51 #endif
53 #include "rb-refstring.h"
54 #include "rb-shell.h"
55 #include "rb-shell-player.h"
56 #include "rb-debug.h"
57 #include "rb-dialog.h"
58 #include "rb-file-helpers.h"
59 #include "rb-stock-icons.h"
60 #include "rb-util.h"
61 #include "eel-gconf-extensions.h"
62 #include "rb-util.h"
64 #if WITH_DBUS
65 #include <dbus/dbus-glib.h>
66 #include "rb-shell-glue.h"
67 #include "rb-shell-player-glue.h"
68 #include "rb-playlist-manager.h"
69 #include "rb-playlist-manager-glue.h"
70 #elif WITH_OLD_DBUS
71 #include <dbus/dbus.h>
72 #include <dbus/dbus-glib.h>
73 #include <dbus/dbus-glib-lowlevel.h>
74 #endif
76 #define HAVE_LIBGNOME_GOPTION defined(GNOME_PARAM_GOPTION_CONTEXT)
78 static gboolean debug = FALSE;
79 static char *debug_match = NULL;
80 static gboolean quit = FALSE;
81 static gboolean no_registration = FALSE;
82 static gboolean no_update = FALSE;
83 static gboolean dry_run = FALSE;
84 static char *rhythmdb_file = NULL;
85 static char *playlists_file = NULL;
86 static char **remaining_args = NULL;
88 #if WITH_DBUS
89 static gboolean load_uri_args (const char **args, GFunc handler, gpointer user_data);
90 static void dbus_load_uri (const char *filename, DBusGProxy *proxy);
91 #endif
93 static void main_shell_weak_ref_cb (gpointer data, GObject *objptr);
95 #if WITH_OLD_DBUS
96 static void register_dbus_handler (DBusConnection *connection, RBShell *shell);
97 static gboolean send_present_message (DBusConnection *connection, guint32 current_time);
99 #endif
102 main (int argc, char **argv)
104 GnomeProgram *program = NULL;
105 #if WITH_DBUS || WITH_OLD_DBUS
106 DBusGConnection *session_bus;
107 GError *error = NULL;
108 #endif
109 RBShell *rb_shell;
110 char **new_argv;
111 gboolean activated;
114 GOptionContext *context;
115 static const GOptionEntry options [] = {
116 { "debug", 'd', 0, G_OPTION_ARG_NONE, &debug, N_("Enable debug output"), NULL },
117 { "debug-match", 'D', 0, G_OPTION_ARG_STRING, &debug_match, N_("Enable debug output matching a specified string"), NULL },
118 { "no-update", 0, 0, G_OPTION_ARG_NONE, &no_update, N_("Do not update the library with file changes"), NULL },
119 { "no-registration", 'n', 0, G_OPTION_ARG_NONE, &no_registration, N_("Do not register the shell"), NULL },
120 { "dry-run", 0, 0, G_OPTION_ARG_NONE, &dry_run, N_("Don't save any data permanently (implies --no-registration)"), NULL },
121 { "rhythmdb-file", 0, 0, G_OPTION_ARG_STRING, &rhythmdb_file, N_("Path for database file to use"), NULL },
122 { "playlists-file", 0, 0, G_OPTION_ARG_STRING, &playlists_file, N_("Path for playlists file to use"), NULL },
123 { "quit", 'q', 0, G_OPTION_ARG_NONE, &quit, N_("Quit Rhythmbox"), NULL },
124 { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_STRING_ARRAY, &remaining_args, NULL, N_("[URI...]") },
125 { NULL }
128 rb_profile_start ("starting rhythmbox");
130 context = g_option_context_new (NULL);
131 g_option_context_add_main_entries (context, options, GETTEXT_PACKAGE);
133 /* Disable event sounds for now by passing "--disable-sound" to libgnomeui.
134 * See: http://bugzilla.gnome.org/show_bug.cgi?id=119222 */
135 new_argv = g_strdupv (argv);
136 new_argv = g_realloc (new_argv, (argc+2)*sizeof(char*));
137 new_argv[argc] = g_strdup ("--disable-sound");
138 new_argv[argc+1] = NULL;
140 #ifdef HAVE_GSTREAMER_0_8
141 /* To pass options to GStreamer in 0.8, RB needs to use popt, for
142 * now, GStreamer can live without them (people can still use env
143 * vars, after all) */
144 gst_init (NULL, NULL);
145 #elif HAVE_GSTREAMER_0_10
146 rb_profile_start ("initializing gstreamer");
147 g_option_context_add_group (context, gst_init_get_option_group ());
148 rb_profile_end ("initializing gstreamer");
149 #endif
151 gtk_set_locale ();
152 rb_profile_start ("initializing gnome program");
154 #if HAVE_LIBGNOME_GOPTION
155 program = gnome_program_init (PACKAGE, VERSION,
156 LIBGNOMEUI_MODULE,
157 argc+1, new_argv,
158 GNOME_PARAM_GOPTION_CONTEXT, context,
159 GNOME_PARAM_HUMAN_READABLE_NAME, _("Rhythmbox"),
160 GNOME_PARAM_APP_DATADIR, DATADIR,
161 NULL);
162 #else
163 g_option_context_parse (context, &argc, &argv, NULL);
164 g_option_context_free (context);
165 program = gnome_program_init (PACKAGE, VERSION,
166 LIBGNOMEUI_MODULE,
167 argc+1, new_argv,
168 GNOME_PARAM_HUMAN_READABLE_NAME, _("Rhythmbox"),
169 GNOME_PARAM_APP_DATADIR, DATADIR,
170 NULL);
171 #endif
173 rb_profile_end ("initializing gnome program");
175 rb_profile_start ("initializing gnome auth manager");
176 gnome_authentication_manager_init ();
177 rb_profile_end ("initializing gnome auth manager");
179 g_random_set_seed (time (0));
181 #ifdef ENABLE_NLS
182 /* initialize i18n */
183 bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
184 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
186 /* ask for utf-8 message text from GStreamer too,
187 * since it doesn't do that itself.
189 #ifdef HAVE_GSTREAMER_0_10
190 bind_textdomain_codeset ("gstreamer-0.10", "UTF-8");
191 #else
192 bind_textdomain_codeset ("gstreamer-0.8", "UTF-8");
193 #endif
194 textdomain (GETTEXT_PACKAGE);
195 #endif
197 #ifdef HAVE_GSTREAMER_0_8
198 gst_control_init (&argc, &argv);
199 #endif
201 if (!debug && debug_match)
202 rb_debug_init_match (debug_match);
203 else
204 rb_debug_init (debug);
205 rb_debug ("initializing Rhythmbox %s", VERSION);
207 /* TODO: kill this function */
208 rb_threads_init ();
210 activated = FALSE;
212 #if WITH_DBUS || WITH_OLD_DBUS
213 rb_debug ("going to create DBus object");
215 dbus_g_thread_init ();
217 session_bus = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
218 if (session_bus == NULL) {
219 g_warning ("couldn't connect to session bus: %s", (error) ? error->message : "(null)");
220 g_clear_error (&error);
221 } else if (!no_registration) {
222 guint request_name_reply;
223 int flags;
224 #ifndef DBUS_NAME_FLAG_DO_NOT_QUEUE
225 flags = DBUS_NAME_FLAG_PROHIBIT_REPLACEMENT;
226 #else
227 flags = DBUS_NAME_FLAG_DO_NOT_QUEUE;
228 #endif
230 #ifndef WITH_OLD_DBUS
231 DBusGProxy *bus_proxy;
233 bus_proxy = dbus_g_proxy_new_for_name (session_bus,
234 "org.freedesktop.DBus",
235 "/org/freedesktop/DBus",
236 "org.freedesktop.DBus");
238 if (!dbus_g_proxy_call (bus_proxy,
239 "RequestName",
240 &error,
241 G_TYPE_STRING,
242 "org.gnome.Rhythmbox",
243 G_TYPE_UINT,
244 flags,
245 G_TYPE_INVALID,
246 G_TYPE_UINT,
247 &request_name_reply,
248 G_TYPE_INVALID)) {
249 g_warning ("Failed to invoke RequestName: %s",
250 error->message);
252 g_object_unref (bus_proxy);
254 #else
255 DBusError dbus_error = {0,};
256 DBusConnection *connection;
258 connection = dbus_g_connection_get_connection (session_bus);
259 request_name_reply = dbus_bus_request_name (connection,
260 "org.gnome.Rhythmbox",
261 flags,
262 &dbus_error);
263 if (dbus_error_is_set (&dbus_error)) {
264 g_warning ("Failed to invoke RequestName: %s",
265 dbus_error.message);
267 dbus_error_free (&dbus_error);
268 #endif
269 if (request_name_reply == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER
270 || request_name_reply == DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER)
271 activated = FALSE;
272 else if (request_name_reply == DBUS_REQUEST_NAME_REPLY_EXISTS
273 || request_name_reply == DBUS_REQUEST_NAME_REPLY_IN_QUEUE)
274 activated = TRUE;
275 else {
276 g_warning ("Got unhandled reply %u from RequestName",
277 request_name_reply);
278 activated = FALSE;
281 #endif
283 if (!activated) {
284 if (quit) {
285 rb_debug ("was asked to quit, but no instance was running");
286 gdk_notify_startup_complete ();
287 exit (0);
289 #ifdef WITH_RHYTHMDB_GDA
290 gda_init (PACKAGE, VERSION, argc, argv);
291 #endif
293 rb_refstring_system_init ();
295 rb_file_helpers_init ();
297 rb_debug ("Going to create a new shell");
299 glade_gnome_init ();
301 rb_stock_icons_init ();
303 gtk_window_set_default_icon_name ("rhythmbox");
305 rb_shell = rb_shell_new (argc, argv, no_registration, no_update, dry_run, rhythmdb_file, playlists_file);
306 g_object_weak_ref (G_OBJECT (rb_shell), main_shell_weak_ref_cb, NULL);
307 if (!no_registration && session_bus != NULL) {
308 #if WITH_DBUS
309 GObject *obj;
310 const char *path;
312 dbus_g_object_type_install_info (RB_TYPE_SHELL, &dbus_glib_rb_shell_object_info);
313 dbus_g_connection_register_g_object (session_bus, "/org/gnome/Rhythmbox/Shell", G_OBJECT (rb_shell));
315 /* register player object */
316 dbus_g_object_type_install_info (RB_TYPE_SHELL_PLAYER, &dbus_glib_rb_shell_player_object_info);
317 obj = rb_shell_get_player (rb_shell);
318 path = rb_shell_get_player_path (rb_shell);
319 dbus_g_connection_register_g_object (session_bus, path, obj);
321 /* register playlist manager object */
322 dbus_g_object_type_install_info (RB_TYPE_PLAYLIST_MANAGER, &dbus_glib_rb_playlist_manager_object_info);
323 obj = rb_shell_get_playlist_manager (rb_shell);
324 path = rb_shell_get_playlist_manager_path (rb_shell);
325 dbus_g_connection_register_g_object (session_bus, path, obj);
326 #elif WITH_OLD_DBUS
327 register_dbus_handler (dbus_g_connection_get_connection (session_bus),
328 rb_shell);
329 #endif /* WITH_DBUS */
331 } else if (!no_registration && session_bus != NULL) {
332 #if WITH_DBUS
333 DBusGProxy *shell_proxy;
334 #endif
335 guint32 current_time;
336 #if GTK_MINOR_VERSION >= 8
337 current_time = gdk_x11_display_get_user_time (gdk_display_get_default ());
338 #else
339 /* FIXME - this does not work; it will return 0 since
340 * we're not in an event. When we pass this to
341 * gtk_window_present_with_time, it ignores the value
342 * since it's 0. The only alternative is to parse the
343 * startup-notification junk from the environment
344 * ourself...
346 current_time = GDK_CURRENT_TIME;
347 #endif /* GTK_MINOR_VERSION */
349 #if WITH_DBUS
350 shell_proxy = dbus_g_proxy_new_for_name_owner (session_bus,
351 "org.gnome.Rhythmbox",
352 "/org/gnome/Rhythmbox/Shell",
353 "org.gnome.Rhythmbox.Shell",
354 &error);
355 if (!shell_proxy) {
356 g_warning ("Couldn't create proxy for Rhythmbox shell: %s",
357 error->message);
358 } else {
359 if (quit) {
360 dbus_g_proxy_call_no_reply (shell_proxy, "quit",
361 G_TYPE_INVALID);
362 } else {
363 load_uri_args ((const char **) remaining_args, (GFunc) dbus_load_uri, shell_proxy);
364 dbus_g_proxy_call_no_reply (shell_proxy, "present",
365 G_TYPE_UINT, current_time,
366 G_TYPE_INVALID);
368 g_object_unref (G_OBJECT (shell_proxy));
370 #elif WITH_OLD_DBUS
371 if (!send_present_message (dbus_g_connection_get_connection (session_bus),
372 current_time))
373 g_warning ("Unable to send dbus message to existing rhythmbox instance");
374 #endif /* WITH_DBUS */
377 if (activated) {
378 gdk_notify_startup_complete ();
379 } else {
381 rb_profile_start ("mainloop");
382 gtk_main ();
383 rb_profile_end ("mainloop");
385 rb_debug ("out of toplevel loop");
387 rb_file_helpers_shutdown ();
388 rb_stock_icons_shutdown ();
389 rb_refstring_system_shutdown ();
391 gnome_vfs_shutdown ();
394 #ifdef HAVE_GSTREAMER_0_10
395 gst_deinit ();
396 #endif
398 g_strfreev (new_argv);
400 rb_debug ("THE END");
401 rb_profile_end ("starting rhythmbox");
402 g_object_unref (program);
404 gnome_accelerators_sync ();
406 exit (0);
409 #if WITH_DBUS
410 static gboolean
411 load_uri_args (const char **args, GFunc handler, gpointer user_data)
413 gboolean handled;
414 guint i;
416 handled = FALSE;
417 for (i = 0; args && args[i]; i++) {
418 char *uri;
420 rb_debug ("examining argument %s", args[i]);
422 uri = gnome_vfs_make_uri_from_shell_arg (args[i]);
424 if (rb_uri_is_local (uri) == FALSE || rb_uri_exists (uri)) {
425 handler (uri, user_data);
427 g_free (uri);
429 handled = TRUE;
431 return handled;
434 static void
435 dbus_load_uri (const char *filename, DBusGProxy *proxy)
437 GError *error = NULL;
438 rb_debug ("Sending loadURI for %s", filename);
439 if (!dbus_g_proxy_call (proxy, "loadURI", &error,
440 G_TYPE_STRING, filename,
441 G_TYPE_BOOLEAN, TRUE,
442 G_TYPE_INVALID,
443 G_TYPE_INVALID))
444 g_printerr ("Failed to load %s: %s",
445 filename, error->message);
447 #endif
449 static void
450 main_shell_weak_ref_cb (gpointer data, GObject *objptr)
452 rb_debug ("caught shell finalization");
453 gtk_main_quit ();
456 #ifdef WITH_OLD_DBUS
457 /* old dbus support (0.31-0.34) */
459 static gboolean
460 send_present_message (DBusConnection *connection, guint32 current_time)
462 DBusMessage *message;
463 gboolean result;
465 message = dbus_message_new_method_call ("org.gnome.Rhythmbox",
466 "/org/gnome/Rhythmbox/Shell",
467 "org.gnome.Rhythmbox.Shell",
468 "present");
469 if (!message)
470 return FALSE;
472 if (!dbus_message_append_args (message,
473 DBUS_TYPE_UINT32, &current_time,
474 DBUS_TYPE_INVALID)) {
475 dbus_message_unref (message);
476 return FALSE;
479 result = dbus_connection_send (connection, message, NULL);
480 dbus_message_unref (message);
482 return result;
485 static void
486 unregister_dbus_handler (DBusConnection *connection, void *data)
488 /* nothing */
491 static DBusHandlerResult
492 handle_dbus_message (DBusConnection *connection, DBusMessage *message, void *data)
494 RBShell *shell = (RBShell *)data;
496 rb_debug ("Handling dbus message");
497 if (dbus_message_is_method_call (message, "org.gnome.Rhythmbox.Shell", "present")) {
498 DBusMessageIter iter;
499 guint32 current_time;
501 if (!dbus_message_iter_init (message, &iter))
502 return DBUS_HANDLER_RESULT_NEED_MEMORY;
504 if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_UINT32)
505 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
507 dbus_message_iter_get_basic (&iter, &current_time);
509 rb_shell_present (shell, current_time, NULL);
510 return DBUS_HANDLER_RESULT_HANDLED;
511 } else {
512 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
516 static void
517 register_dbus_handler (DBusConnection *connection, RBShell *shell)
519 DBusObjectPathVTable vt = {
520 unregister_dbus_handler,
521 handle_dbus_message,
522 NULL, NULL, NULL, NULL
525 dbus_connection_register_object_path (connection,
526 "/org/gnome/Rhythmbox/Shell",
527 &vt,
528 shell);
529 dbus_connection_ref (connection);
530 dbus_connection_setup_with_g_main (connection, NULL);
533 #endif