[rhythmbox] shell: convert the shell into a GtkApplication
- From: Jonathan Matthew <jmatthew src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [rhythmbox] shell: convert the shell into a GtkApplication
- Date: Wed, 28 Sep 2011 23:46:51 +0000 (UTC)
commit fa9a352b67347c9aa4f516052f3f1ef5a0b53dc6
Author: Jonathan Matthew <jonathan d14n org>
Date: Thu Sep 29 09:30:34 2011 +1000
shell: convert the shell into a GtkApplication
This mostly replaces the shell dbus interface. We're now using
org.gnome.Rhythmbox3 as the dbus name since old dbus clients will not
be able to talk to rhythmbox 3+ from here on.
.gitignore | 2 +-
bindings/vala/rb.vapi | 1 -
configure.ac | 14 +-
data/Makefile.am | 4 +-
....service.in => org.gnome.Rhythmbox3.service.in} | 2 +-
shell/Makefile.am | 7 -
shell/main.c | 339 +---
shell/rb-shell.c | 2706 ++++++++++----------
shell/rb-shell.h | 29 +-
shell/rb-shell.xml | 93 -
10 files changed, 1415 insertions(+), 1782 deletions(-)
---
diff --git a/.gitignore b/.gitignore
index 959f343..f623a7f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -36,7 +36,7 @@ bindings/gi/RB-3.0.gir
bindings/gi/RB-3.0.typelib
#
-org.gnome.Rhythmbox.service
+org.gnome.Rhythmbox3.service
*.desktop
rhythmbox.desktop.in
rhythmbox-device.desktop.in
diff --git a/bindings/vala/rb.vapi b/bindings/vala/rb.vapi
index 411ac8b..84c0970 100644
--- a/bindings/vala/rb.vapi
+++ b/bindings/vala/rb.vapi
@@ -19,7 +19,6 @@ namespace RB {
public void add_widget (Gtk.Widget widget, RB.ShellUILocation location);
public void remove_widget (Gtk.Widget widget, RB.ShellUILocation location);
- public GLib.Object get_ui_manager ();
[NoAccessorMethod]
public RhythmDB.DB db { owned get; }
diff --git a/configure.ac b/configure.ac
index 1da1e2e..87273dd 100644
--- a/configure.ac
+++ b/configure.ac
@@ -45,7 +45,6 @@ AC_CHECK_SIZEOF(long)
GTK_REQS=2.91.4
-DBUS_MIN_REQS=0.35
GST_0_10_REQS=0.10.32
GDK_PIXBUF_REQS=2.18.0
GLIB_REQS=2.26.0
@@ -144,14 +143,14 @@ AC_ARG_WITH(hal,
AC_HELP_STRING([--without-hal],
[Disable HAL support]))
if test "x$with_hal" != "xno"; then
- PKG_CHECK_MODULES(HAL, hal >= 0.5 hal < 0.6, enable_hal=yes, enable_hal=no)
+ PKG_CHECK_MODULES(HAL, hal >= 0.5 hal < 0.6 dbus-glib-1, enable_hal=yes, enable_hal=no)
if test "x$enable_hal" != "xyes" -a "x$with_hal" = "xyes"; then
AC_MSG_ERROR([HAL support explicitly requested but HAL couldn't be found])
fi
if test "x$enable_hal" = "xyes"; then
- AC_DEFINE(HAVE_HAL, 1, [Define if you have HAL support])
- AC_SUBST(HAL_CFLAGS)
+ AC_DEFINE(HAVE_HAL, 1, [Define if you have HAL support])
+ AC_SUBST(HAL_CFLAGS)
AC_SUBST(HAL_LIBS)
fi
fi
@@ -471,13 +470,6 @@ AC_SUBST(mkdir_p) if test x"$mkdir_p" = "x"; then
fi
AC_SUBST(MKINSTALLDIRS)
-dnl DBUS
-PKG_CHECK_MODULES(DBUS, dbus-glib-1 >= $DBUS_MIN_REQS)
-
-DBUS_CFLAGS="$DBUS_CFLAGS -DDBUS_API_SUBJECT_TO_CHANGE"
-DBUS_GLIB_BIN="`$PKG_CONFIG --variable=exec_prefix dbus-glib-1`/bin"
-AC_SUBST(DBUS_GLIB_BIN)
-
AM_GCONF_SOURCE_2
dnl LIRC
diff --git a/data/Makefile.am b/data/Makefile.am
index ff52c31..d29ea7c 100644
--- a/data/Makefile.am
+++ b/data/Makefile.am
@@ -30,7 +30,7 @@ all-local: gschemas.compiled
# Dbus service file
servicedir = $(datadir)/dbus-1/services
-service_in_files = org.gnome.Rhythmbox.service.in
+service_in_files = org.gnome.Rhythmbox3.service.in
service_DATA = $(service_in_files:.service.in=.service)
# Rule to make the service file with bindir expanded
@@ -62,7 +62,7 @@ EXTRA_DIST = $(service_in_files) \
CLEANFILES = \
rhythmbox.desktop \
rhythmbox-device.desktop \
- org.gnome.Rhythmbox.service \
+ org.gnome.Rhythmbox3.service \
playlists.xml \
rhythmbox.desktop.in \
rhythmbox-device.desktop.in \
diff --git a/data/org.gnome.Rhythmbox.service.in b/data/org.gnome.Rhythmbox3.service.in
similarity index 60%
rename from data/org.gnome.Rhythmbox.service.in
rename to data/org.gnome.Rhythmbox3.service.in
index d68cba0..30c70d8 100644
--- a/data/org.gnome.Rhythmbox.service.in
+++ b/data/org.gnome.Rhythmbox3.service.in
@@ -1,3 +1,3 @@
[D-BUS Service]
-Name=org.gnome.Rhythmbox
+Name=org.gnome.Rhythmbox3
Exec= bindir@/rhythmbox
diff --git a/shell/Makefile.am b/shell/Makefile.am
index a14c718..7064391 100644
--- a/shell/Makefile.am
+++ b/shell/Makefile.am
@@ -123,13 +123,6 @@ librhythmbox_core_la_LDFLAGS = \
-export-dynamic -no-undefined
librhythmbox_core_la_LIBTOOLFLAGS = --tag=disable-static
-rb-shell-glue.h: rb-shell.xml Makefile
- $(LIBTOOL) --mode=execute $(DBUS_GLIB_BIN)/dbus-binding-tool --prefix=rb_shell --mode=glib-server --output=$@ $<
-rb-shell-binding.h: rb-shell.xml Makefile
- $(LIBTOOL) --mode=execute $(DBUS_GLIB_BIN)/dbus-binding-tool --prefix=rb_shell --mode=glib-client --output=$@ $<
-
-BUILT_SOURCES += rb-shell-glue.h rb-shell-binding.h
-EXTRA_DIST += rb-shell.xml
rhythmbox_LDADD = \
librhythmbox-core.la \
diff --git a/shell/main.c b/shell/main.c
index 56fd488..6c6db54 100644
--- a/shell/main.c
+++ b/shell/main.c
@@ -29,96 +29,25 @@
#include <config.h>
-#ifdef ENABLE_PYTHON
-/* pyconfig.h usually defines _XOPEN_SOURCE */
-#undef _XOPEN_SOURCE
-#define NO_IMPORT_PYGOBJECT
-#include <pygobject.h>
-#include "rb-python-module.h"
-
-/* make sure it's defined somehow */
-#ifndef _XOPEN_SOURCE
-#define _XOPEN_SOURCE
-#endif
-#endif
-
-#include <stdlib.h>
-#include <unistd.h>
-#include <time.h>
-#include <string.h>
-#include <libintl.h>
-#include <locale.h>
-
#include <glib/gi18n.h>
-#include <gdk/gdkx.h> /* For _get_user_time... */
#include <gtk/gtk.h>
-#include <gst/gst.h>
-
-#ifdef WITH_RHYTHMDB_GDA
-#include <libgda/libgda.h>
-#endif
-
#include <girepository.h>
-#include "rb-refstring.h"
#include "rb-shell.h"
-#include "rb-shell-player.h"
-#include "rb-debug.h"
-#include "rb-dialog.h"
-#include "rb-file-helpers.h"
-#include "rb-stock-icons.h"
#include "rb-util.h"
#include "eggdesktopfile.h"
#include "eggsmclient.h"
-
-#include <dbus/dbus-glib.h>
-#include "rb-shell-glue.h"
-#include "rb-playlist-manager.h"
-
-
-static gboolean debug = FALSE;
-static char *debug_match = NULL;
-static gboolean quit = FALSE;
-static gboolean no_registration = FALSE;
-static gboolean no_update = FALSE;
-static gboolean dry_run = FALSE;
-static gboolean disable_plugins = FALSE;
-static char *rhythmdb_file = NULL;
-static char *playlists_file = NULL;
-static char **remaining_args = NULL;
-
-static gboolean load_uri_args (const char **args, GFunc handler, gpointer user_data);
-static void dbus_load_uri (const char *filename, DBusGProxy *proxy);
-static void database_load_complete (RBShell *shell, gpointer data);
-static void local_load_uri (const char *filename, RBShell *shell);
-
-static void main_shell_weak_ref_cb (gpointer data, GObject *objptr);
+#include "rb-debug.h"
int
main (int argc, char **argv)
{
- DBusGConnection *session_bus;
- GError *error = NULL;
- RBShell *rb_shell;
- gboolean activated;
+ RBShell *shell;
gboolean autostarted;
char *desktop_file_path;
-
- GOptionContext *context;
- static const GOptionEntry options [] = {
- { "debug", 'd', 0, G_OPTION_ARG_NONE, &debug, N_("Enable debug output"), NULL },
- { "debug-match", 'D', 0, G_OPTION_ARG_STRING, &debug_match, N_("Enable debug output matching a specified string"), NULL },
- { "no-update", 0, 0, G_OPTION_ARG_NONE, &no_update, N_("Do not update the library with file changes"), NULL },
- { "no-registration", 'n', 0, G_OPTION_ARG_NONE, &no_registration, N_("Do not register the shell"), NULL },
- { "dry-run", 0, 0, G_OPTION_ARG_NONE, &dry_run, N_("Don't save any data permanently (implies --no-registration)"), NULL },
- { "disable-plugins", 0, 0, G_OPTION_ARG_NONE, &disable_plugins, N_("Disable loading of plugins"), NULL },
- { "rhythmdb-file", 0, 0, G_OPTION_ARG_STRING, &rhythmdb_file, N_("Path for database file to use"), NULL },
- { "playlists-file", 0, 0, G_OPTION_ARG_STRING, &playlists_file, N_("Path for playlists file to use"), NULL },
- { "quit", 'q', 0, G_OPTION_ARG_NONE, &quit, N_("Quit Rhythmbox"), NULL },
- { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_STRING_ARRAY, &remaining_args, NULL, N_("[URI...]") },
- { NULL }
- };
+ int new_argc;
+ char **new_argv;
/* disable multidevice so clutter-gtk events work.
* this needs to be done before gtk_open, so the visualizer
@@ -126,8 +55,8 @@ main (int argc, char **argv)
*/
gdk_disable_multidevice ();
g_thread_init (NULL);
-
- rb_profile_start ("starting rhythmbox");
+ g_type_init ();
+ g_random_set_seed (time (0));
autostarted = (g_getenv ("DESKTOP_AUTOSTART_ID") != NULL);
@@ -141,49 +70,16 @@ main (int argc, char **argv)
egg_set_desktop_file (desktop_file_path);
g_free (desktop_file_path);
- context = g_option_context_new (NULL);
- g_option_context_add_main_entries (context, options, GETTEXT_PACKAGE);
-
- rb_profile_start ("initializing gstreamer");
- g_option_context_add_group (context, gst_init_get_option_group ());
- rb_profile_end ("initializing gstreamer");
-
- g_option_context_add_group (context, egg_sm_client_get_option_group ());
- g_option_context_add_group (context, gtk_get_option_group (TRUE));
-
setlocale (LC_ALL, NULL);
- rb_profile_start ("parsing command line options");
- if (g_option_context_parse (context, &argc, &argv, &error) == FALSE) {
- g_print (_("%s\nRun '%s --help' to see a full list of available command line options.\n"),
- error->message, argv[0]);
- g_error_free (error);
- g_option_context_free (context);
- exit (1);
- }
- g_option_context_free (context);
- rb_profile_end ("parsing command line options");
-
- g_random_set_seed (time (0));
-
#ifdef ENABLE_NLS
/* initialize i18n */
bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
- /* ask for utf-8 message text from GStreamer too,
- * since it doesn't do that itself.
- */
- bind_textdomain_codeset ("gstreamer-0.10", "UTF-8");
textdomain (GETTEXT_PACKAGE);
#endif
- if (!debug && debug_match)
- rb_debug_init_match (debug_match);
- else
- rb_debug_init (debug);
- rb_debug ("initializing Rhythmbox %s", VERSION);
-
#if defined(USE_UNINSTALLED_DIRS)
g_irepository_prepend_search_path (SHARE_UNINSTALLED_BUILDDIR "/../bindings/gi");
#endif
@@ -192,228 +88,15 @@ main (int argc, char **argv)
rb_threads_init ();
gdk_threads_enter ();
- activated = FALSE;
-
- rb_debug ("going to create DBus object");
-
- dbus_g_thread_init ();
+ new_argc = argc;
+ new_argv = argv;
+ shell = rb_shell_new (autostarted, &argc, &argv);
- session_bus = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
- if (session_bus == NULL) {
- g_warning ("couldn't connect to session bus: %s", (error) ? error->message : "(null)");
- g_clear_error (&error);
- } else if (!no_registration) {
- guint request_name_reply;
- int flags;
-#ifndef DBUS_NAME_FLAG_DO_NOT_QUEUE
- flags = DBUS_NAME_FLAG_PROHIBIT_REPLACEMENT;
-#else
- flags = DBUS_NAME_FLAG_DO_NOT_QUEUE;
-#endif
-
- DBusGProxy *bus_proxy;
-
- bus_proxy = dbus_g_proxy_new_for_name (session_bus,
- "org.freedesktop.DBus",
- "/org/freedesktop/DBus",
- "org.freedesktop.DBus");
-
- if (!dbus_g_proxy_call (bus_proxy,
- "RequestName",
- &error,
- G_TYPE_STRING,
- "org.gnome.Rhythmbox",
- G_TYPE_UINT,
- flags,
- G_TYPE_INVALID,
- G_TYPE_UINT,
- &request_name_reply,
- G_TYPE_INVALID)) {
- g_warning ("Failed to invoke RequestName: %s",
- error->message);
- }
- g_object_unref (bus_proxy);
+ g_application_run (G_APPLICATION (shell), new_argc, new_argv);
- if (request_name_reply == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER
- || request_name_reply == DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER)
- activated = FALSE;
- else if (request_name_reply == DBUS_REQUEST_NAME_REPLY_EXISTS
- || request_name_reply == DBUS_REQUEST_NAME_REPLY_IN_QUEUE)
- activated = TRUE;
- else {
- g_warning ("Got unhandled reply %u from RequestName",
- request_name_reply);
- activated = FALSE;
- }
- }
-
- if (!activated) {
- if (quit) {
- rb_debug ("was asked to quit, but no instance was running");
- gdk_notify_startup_complete ();
- exit (0);
- }
-#ifdef WITH_RHYTHMDB_GDA
- gda_init (PACKAGE, VERSION, argc, argv);
-#endif
-
- rb_refstring_system_init ();
-
-#ifdef USE_UNINSTALLED_DIRS
- rb_file_helpers_init (TRUE);
-#else
- rb_file_helpers_init (FALSE);
-#endif
- rb_debug ("Going to create a new shell");
-
- rb_stock_icons_init ();
-
- g_setenv ("PULSE_PROP_media.role", "music", TRUE);
-
- rb_shell = rb_shell_new (no_registration, no_update, dry_run, autostarted, disable_plugins, rhythmdb_file, playlists_file);
- g_object_weak_ref (G_OBJECT (rb_shell), main_shell_weak_ref_cb, NULL);
- if (!no_registration && session_bus != NULL) {
- dbus_g_object_type_install_info (RB_TYPE_SHELL, &dbus_glib_rb_shell_object_info);
- dbus_g_connection_register_g_object (session_bus, "/org/gnome/Rhythmbox/Shell", G_OBJECT (rb_shell));
-
- g_signal_connect (G_OBJECT (rb_shell),
- "database-load-complete",
- G_CALLBACK (database_load_complete),
- NULL);
- }
- } else if (!no_registration && session_bus != NULL) {
- DBusGProxy *shell_proxy;
- guint32 current_time;
- current_time = gdk_x11_display_get_user_time (gdk_display_get_default ());
- shell_proxy = dbus_g_proxy_new_for_name_owner (session_bus,
- "org.gnome.Rhythmbox",
- "/org/gnome/Rhythmbox/Shell",
- "org.gnome.Rhythmbox.Shell",
- &error);
- if (!shell_proxy) {
- g_warning ("Couldn't create proxy for Rhythmbox shell: %s",
- error->message);
- } else {
- if (quit) {
- dbus_g_proxy_call_no_reply (shell_proxy, "quit",
- G_TYPE_INVALID);
- } else {
- load_uri_args ((const char **) remaining_args, (GFunc) dbus_load_uri, shell_proxy);
- dbus_g_proxy_call_no_reply (shell_proxy, "present",
- G_TYPE_UINT, current_time,
- G_TYPE_INVALID);
- }
- g_object_unref (G_OBJECT (shell_proxy));
- }
- }
-
- if (activated) {
- gdk_notify_startup_complete ();
- } else {
-
- rb_profile_start ("mainloop");
-#ifdef ENABLE_PYTHON
- if (rb_python_init_successful ()) {
- pyg_begin_allow_threads;
- gtk_main ();
- pyg_end_allow_threads;
- } else {
- gtk_main ();
- }
-#else
- gtk_main ();
-#endif
- rb_profile_end ("mainloop");
-
- rb_debug ("out of toplevel loop");
-
- rb_file_helpers_shutdown ();
- rb_stock_icons_shutdown ();
- rb_refstring_system_shutdown ();
- }
-
- gst_deinit ();
-
- rb_debug ("THE END");
- rb_profile_end ("starting rhythmbox");
+ g_object_unref (shell);
gdk_threads_leave ();
exit (0);
}
-
-static gboolean
-load_uri_args (const char **args, GFunc handler, gpointer user_data)
-{
- gboolean handled;
- guint i;
-
- handled = FALSE;
- for (i = 0; args && args[i]; i++) {
- GFile *file;
- char *uri;
-
- rb_debug ("examining argument %s", args[i]);
-
- file = g_file_new_for_commandline_arg (args[i]);
- uri = g_file_get_uri (file);
-
- /*
- * rb_uri_exists won't work if the location isn't mounted.
- * however, things that are interesting to mount are generally
- * non-local, so we'll process them anyway.
- */
- if (rb_uri_is_local (uri) == FALSE || rb_uri_exists (uri)) {
- handler (uri, user_data);
- }
- g_free (uri);
- g_object_unref (file);
-
- handled = TRUE;
- }
- return handled;
-}
-
-static void
-dbus_load_uri (const char *filename, DBusGProxy *proxy)
-{
- GError *error = NULL;
- rb_debug ("Sending loadURI for %s", filename);
- if (!dbus_g_proxy_call (proxy, "loadURI", &error,
- G_TYPE_STRING, filename,
- G_TYPE_BOOLEAN, TRUE,
- G_TYPE_INVALID,
- G_TYPE_INVALID)) {
- g_printerr ("Failed to load %s: %s",
- filename, error->message);
- g_error_free (error);
- }
-}
-
-static void
-main_shell_weak_ref_cb (gpointer data, GObject *objptr)
-{
- rb_debug ("caught shell finalization");
- gtk_main_quit ();
-}
-
-static void
-database_load_complete (RBShell *shell, gpointer data)
-{
- load_uri_args ((const char **) remaining_args, (GFunc) local_load_uri, shell);
-}
-
-static void
-local_load_uri (const char *filename, RBShell *shell)
-{
- GError *error = NULL;
- rb_debug ("Using load_uri for %s", filename);
- if (!rb_shell_load_uri (shell, filename, TRUE, &error)) {
- if (error != NULL) {
- g_printerr ("Failed to load %s: %s",
- filename, error->message);
- g_error_free (error);
- }
- }
-}
-
diff --git a/shell/rb-shell.c b/shell/rb-shell.c
index 037dd0d..924bc9f 100644
--- a/shell/rb-shell.c
+++ b/shell/rb-shell.c
@@ -52,6 +52,8 @@
#include <libpeas/peas.h>
#include <libpeas-gtk/peas-gtk.h>
+#include <gst/gst.h>
+
#ifdef HAVE_MMKEYS
#include <X11/XF86keysym.h>
#endif /* HAVE_MMKEYS */
@@ -113,6 +115,9 @@ static void rb_shell_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec);
+static void rb_shell_activate (GApplication *app);
+static void rb_shell_open (GApplication *app, GFile **files, int n_files, const char *hint);
+static gboolean rb_shell_local_command_line (GApplication *app, gchar ***args, int *exit_status);
static gboolean rb_shell_get_visibility (RBShell *shell);
static gboolean rb_shell_window_state_cb (GtkWidget *widget,
GdkEventWindowState *event,
@@ -244,16 +249,14 @@ enum
VISIBILITY_CHANGED,
VISIBILITY_CHANGING,
CREATE_SONG_INFO,
- REMOVABLE_MEDIA_SCAN_FINISHED,
NOTIFY_PLAYING_ENTRY,
NOTIFY_CUSTOM,
- DATABASE_LOAD_COMPLETE,
LAST_SIGNAL
};
static guint rb_shell_signals[LAST_SIGNAL] = { 0 };
-G_DEFINE_TYPE (RBShell, rb_shell, G_TYPE_OBJECT)
+G_DEFINE_TYPE (RBShell, rb_shell, GTK_TYPE_APPLICATION)
struct _RBShellPrivate
{
@@ -404,1256 +407,1550 @@ static GtkToggleActionEntry rb_shell_toggle_entries [] =
static guint rb_shell_n_toggle_entries = G_N_ELEMENTS (rb_shell_toggle_entries);
static void
-rb_shell_class_init (RBShellClass *klass)
+rb_shell_activate (GApplication *app)
{
- GObjectClass *object_class = (GObjectClass *) klass;
+ rb_shell_present (RB_SHELL (app), gtk_get_current_event_time (), NULL);
+}
- object_class->set_property = rb_shell_set_property;
- object_class->get_property = rb_shell_get_property;
- object_class->finalize = rb_shell_finalize;
- object_class->constructed = rb_shell_constructed;
+static void
+rb_shell_open (GApplication *app, GFile **files, int n_files, const char *hint)
+{
+ int i;
- klass->visibility_changing = rb_shell_visibility_changing;
+ for (i = 0; i < n_files; i++) {
+ char *uri;
+
+ uri = g_file_get_uri (files[i]);
+
+ /*
+ * rb_uri_exists won't work if the location isn't mounted.
+ * however, things that are interesting to mount are generally
+ * non-local, so we'll process them anyway.
+ */
+ if (rb_uri_is_local (uri) == FALSE || rb_uri_exists (uri)) {
+ rb_shell_load_uri (RB_SHELL (app), uri, TRUE, NULL);
+ }
+ g_free (uri);
+ }
+}
+
+static void
+load_state_changed_cb (GActionGroup *action_group, const char *action_name, GVariant *state, GPtrArray *files)
+{
+ gboolean loaded;
+ gboolean scanned;
+
+ if (g_strcmp0 (action_name, "LoadURI") != 0) {
+ return;
+ }
+
+ g_variant_get (state, "(bb)", &loaded, &scanned);
+ if (loaded) {
+ rb_debug ("opening files now");
+ g_signal_handlers_disconnect_by_func (action_group, load_state_changed_cb, files);
+
+ g_application_open (G_APPLICATION (action_group), (GFile **)files->pdata, files->len, "");
+ g_ptr_array_free (files, TRUE);
+ }
+}
+
+
+
+static GMountOperation *
+rb_shell_create_mount_op_cb (RhythmDB *db, RBShell *shell)
+{
+ /* we don't want the operation to be modal, so we don't associate it with the window. */
+ GMountOperation *op = gtk_mount_operation_new (NULL);
+ gtk_mount_operation_set_screen (GTK_MOUNT_OPERATION (op),
+ gtk_window_get_screen (GTK_WINDOW (shell->priv->window)));
+ return op;
+}
+
+static void
+construct_db (RBShell *shell)
+{
+ char *pathname;
+
+ /* Initialize the database */
+ rb_debug ("creating database object");
+ rb_profile_start ("creating database object");
+
+ if (shell->priv->rhythmdb_file) {
+ pathname = g_strdup (shell->priv->rhythmdb_file);
+ } else {
+ pathname = rb_find_user_data_file ("rhythmdb.xml");
+ }
- /**
- * RBShell:no-registration:
- *
- * If %TRUE, disable single-instance features.
- */
- g_object_class_install_property (object_class,
- PROP_NO_REGISTRATION,
- g_param_spec_boolean ("no-registration",
- "no-registration",
- "Whether or not to register",
- FALSE,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
- /**
- * RBShell:no-update:
- *
- * If %TRUE, don't update the database.
- */
- g_object_class_install_property (object_class,
- PROP_NO_UPDATE,
- g_param_spec_boolean ("no-update",
- "no-update",
- "Whether or not to update the library",
- FALSE,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
- /**
- * RBShell:dry-run:
- *
- * If TRUE, don't write back file metadata changes.
- */
- g_object_class_install_property (object_class,
- PROP_DRY_RUN,
- g_param_spec_boolean ("dry-run",
- "dry-run",
- "Whether or not this is a dry run",
- FALSE,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
- /**
- * RBShell:rhythmdb-file:
- *
- * The path to the rhythmdb file
- */
- g_object_class_install_property (object_class,
- PROP_RHYTHMDB_FILE,
- g_param_spec_string ("rhythmdb-file",
- "rhythmdb-file",
- "The RhythmDB file to use",
#ifdef WITH_RHYTHMDB_TREE
- "rhythmdb.xml",
+ shell->priv->db = rhythmdb_tree_new (pathname);
#elif defined(WITH_RHYTHMDB_GDA)
- "rhythmdb.sqlite", /* FIXME: correct extension? */
+ shell->priv->db = rhythmdb_gda_new (pathname);
#endif
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+ g_free (pathname);
- /**
- * RBShell:playlists-file:
- *
- * The path to the playlist file
- */
- g_object_class_install_property (object_class,
- PROP_PLAYLISTS_FILE,
- g_param_spec_string ("playlists-file",
- "playlists-file",
- "The playlists file to use",
- "playlists.xml",
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+ if (shell->priv->dry_run)
+ g_object_set (shell->priv->db, "dry-run", TRUE, NULL);
+ if (shell->priv->no_update)
+ g_object_set (shell->priv->db, "no-update", TRUE, NULL);
+ g_signal_connect_object (G_OBJECT (shell->priv->db), "load-complete",
+ G_CALLBACK (rb_shell_load_complete_cb), shell,
+ 0);
+ g_signal_connect_object (G_OBJECT (shell->priv->db), "create-mount-op",
+ G_CALLBACK (rb_shell_create_mount_op_cb), shell,
+ 0);
- /**
- * RBShell:selected-page:
- *
- * The currently selected display page
- */
- g_object_class_install_property (object_class,
- PROP_SELECTED_PAGE,
- g_param_spec_object ("selected-page",
- "selected-page",
- "Display page which is currently selected",
- RB_TYPE_DISPLAY_PAGE,
- G_PARAM_READABLE));
- /**
- * RBShell:db:
- *
- * The #RhythmDB instance
- */
- g_object_class_install_property (object_class,
- PROP_DB,
- g_param_spec_object ("db",
- "RhythmDB",
- "RhythmDB object",
- RHYTHMDB_TYPE,
- G_PARAM_READABLE));
- /**
- * RBShell:ui-manager:
- *
- * The #GtkUIManager instance
- */
- g_object_class_install_property (object_class,
- PROP_UI_MANAGER,
- g_param_spec_object ("ui-manager",
- "GtkUIManager",
- "GtkUIManager object",
- GTK_TYPE_UI_MANAGER,
- G_PARAM_READABLE));
- /**
- * RBShell:clipboard:
- *
- * The #RBShellClipboard instance
- */
- g_object_class_install_property (object_class,
- PROP_CLIPBOARD,
- g_param_spec_object ("clipboard",
- "RBShellClipboard",
- "RBShellClipboard object",
- RB_TYPE_SHELL_CLIPBOARD,
- G_PARAM_READABLE));
- /**
- * RBShell:playlist-manager:
- *
- * The #RBPlaylistManager instance
- */
- g_object_class_install_property (object_class,
- PROP_PLAYLIST_MANAGER,
- g_param_spec_object ("playlist-manager",
- "RBPlaylistManager",
- "RBPlaylistManager object",
- RB_TYPE_PLAYLIST_MANAGER,
- G_PARAM_READABLE));
- /**
- * RBShell:shell-player:
- *
- * The #RBShellPlayer instance
- */
- g_object_class_install_property (object_class,
- PROP_SHELL_PLAYER,
- g_param_spec_object ("shell-player",
- "RBShellPlayer",
- "RBShellPlayer object",
- RB_TYPE_SHELL_PLAYER,
- G_PARAM_READABLE));
- /**
- * RBShell:removable-media-manager:
- *
- * The #RBRemovableMediaManager instance
- */
- g_object_class_install_property (object_class,
- PROP_REMOVABLE_MEDIA_MANAGER,
- g_param_spec_object ("removable-media-manager",
- "RBRemovableMediaManager",
- "RBRemovableMediaManager object",
- RB_TYPE_REMOVABLE_MEDIA_MANAGER,
- G_PARAM_READABLE));
- /**
- * RBShell:window:
- *
- * The main Rhythmbox window.
- */
- g_object_class_install_property (object_class,
- PROP_WINDOW,
- g_param_spec_object ("window",
- "GtkWindow",
- "GtkWindow object",
- GTK_TYPE_WINDOW,
- G_PARAM_READABLE));
- /**
- * RBShell:prefs:
- *
- * The #RBShellPreferences instance
- */
- g_object_class_install_property (object_class,
- PROP_PREFS,
- g_param_spec_object ("prefs",
- "RBShellPreferences",
- "RBShellPreferences object",
- RB_TYPE_SHELL_PREFERENCES,
- G_PARAM_READABLE));
- /**
- * RBShell:queue-source:
- *
- * The play queue source
- */
- g_object_class_install_property (object_class,
- PROP_QUEUE_SOURCE,
- g_param_spec_object ("queue-source",
- "queue-source",
- "Queue source",
- RB_TYPE_PLAY_QUEUE_SOURCE,
- G_PARAM_READABLE));
- /**
- * RBShell:library-source:
- *
- * The library source
- */
- g_object_class_install_property (object_class,
- PROP_LIBRARY_SOURCE,
- g_param_spec_object ("library-source",
- "library-source",
- "Library source",
- RB_TYPE_LIBRARY_SOURCE,
- G_PARAM_READABLE));
- /**
- * RBShell:display-page-model:
- *
- * The model underlying the display page tree
- */
- g_object_class_install_property (object_class,
- PROP_DISPLAY_PAGE_MODEL,
- g_param_spec_object ("display-page-model",
- "display-page-model",
- "RBDisplayPageModel",
- RB_TYPE_DISPLAY_PAGE_MODEL,
- G_PARAM_READABLE));
-
- /**
- * RBShell:display-page-tree:
- *
- * The #RBDisplayPageTree instance
- */
- g_object_class_install_property (object_class,
- PROP_DISPLAY_PAGE_TREE,
- g_param_spec_object ("display-page-tree",
- "display-page-tree",
- "RBDisplayPageTree",
- RB_TYPE_DISPLAY_PAGE_TREE,
- G_PARAM_READABLE));
-
- /**
- * RBShell:visibility:
- *
- * Whether the main window is currently visible.
- */
- g_object_class_install_property (object_class,
- PROP_VISIBILITY,
- g_param_spec_boolean ("visibility",
- "visibility",
- "Current window visibility",
- TRUE,
- G_PARAM_READWRITE));
- /**
- * RBShell:source-header:
- *
- * The #RBSourceHeader instance
- */
- g_object_class_install_property (object_class,
- PROP_SOURCE_HEADER,
- g_param_spec_object ("source-header",
- "source header widget",
- "RBSourceHeader",
- RB_TYPE_SOURCE_HEADER,
- G_PARAM_READABLE));
+ rb_profile_end ("creating database object");
+}
- /**
- * RBShell:track-transfer-queue:
- *
- * The #RBTrackTransferQueue instance
- */
- g_object_class_install_property (object_class,
- PROP_TRACK_TRANSFER_QUEUE,
- g_param_spec_object ("track-transfer-queue",
- "RBTrackTransferQueue",
- "RBTrackTransferQueue object",
- RB_TYPE_TRACK_TRANSFER_QUEUE,
- G_PARAM_READABLE));
- /**
- * RBShell:autostarted:
- *
- * Whether Rhythmbox was automatically started by the session manager
- */
- g_object_class_install_property (object_class,
- PROP_AUTOSTARTED,
- g_param_spec_boolean ("autostarted",
- "autostarted",
- "TRUE if autostarted",
- FALSE,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+static void
+construct_widgets (RBShell *shell)
+{
+ GtkWindow *win;
- /**
- * RBShell:disable-plugins:
- *
- * If %TRUE, disable plugins
- */
- g_object_class_install_property (object_class,
- PROP_DISABLE_PLUGINS,
- g_param_spec_boolean ("disable-plugins",
- "disable-plugins",
- "Whether or not to disable plugins",
- FALSE,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+ rb_profile_start ("constructing widgets");
- /**
- * RBShell::visibility-changed:
- * @shell: the #RBShell
- * @visibile: new visibility
- *
- * Emitted after the visibility of the main Rhythmbox window has
- * changed.
- */
- rb_shell_signals[VISIBILITY_CHANGED] =
- g_signal_new ("visibility_changed",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (RBShellClass, visibility_changed),
- NULL, NULL,
- g_cclosure_marshal_VOID__BOOLEAN,
- G_TYPE_NONE,
- 1,
- G_TYPE_BOOLEAN);
- /**
- * RBShell::visibility-changing:
- * @shell: the #RBShell
- * @initial: if %TRUE, this is the initial visibility for the window
- * @visible: new shell visibility
- *
- * Emitted before the visibility of the main window changes. The return
- * value overrides the visibility setting. If multiple signal handlers
- * are attached, the last one wins.
- */
- rb_shell_signals[VISIBILITY_CHANGING] =
- g_signal_new ("visibility_changing",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (RBShellClass, visibility_changing),
- NULL, NULL,
- rb_marshal_BOOLEAN__BOOLEAN_BOOLEAN,
- G_TYPE_BOOLEAN,
- 2,
- G_TYPE_BOOLEAN,
- G_TYPE_BOOLEAN);
+ /* initialize UI */
+ win = GTK_WINDOW (gtk_window_new (GTK_WINDOW_TOPLEVEL));
+ gtk_window_set_title (win, _("Rhythmbox"));
- /**
- * RBShell::create-song-info:
- * @shell: the #RBShell
- * @song_info: the new #RBSongInfo window
- * @multi: if %TRUE, the song info window is for multiple entries
- *
- * Emitted when creating a new #RBSongInfo window. Signal handlers can
- * add pages to the song info window notebook to display additional
- * information.
- */
- rb_shell_signals[CREATE_SONG_INFO] =
- g_signal_new ("create_song_info",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (RBShellClass, create_song_info),
- NULL, NULL,
- rb_marshal_VOID__OBJECT_BOOLEAN,
- G_TYPE_NONE,
- 2,
- RB_TYPE_SONG_INFO, G_TYPE_BOOLEAN);
- /**
- * RBShell::removable-media-scan-finished:
- * @shell: the #RBShell
- *
- * Emitted when the initial scan for removable media devices is
- * complete. This is intended to allow plugins to request a
- * device scan only if the scan on startup has already been done,
- * but it isn't very useful for that.
- * See #RBRemovableMediaManager:scanned for a better approach to
- * this problem.
- */
- rb_shell_signals[REMOVABLE_MEDIA_SCAN_FINISHED] =
- g_signal_new ("removable_media_scan_finished",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (RBShellClass, removable_media_scan_finished),
- NULL, NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE,
- 0);
- /**
- * RBShell::notify-playing-entry:
- * @shell: the #RBShell
- *
- * Emitted when a notification should be displayed showing the current
- * playing entry.
- */
- rb_shell_signals[NOTIFY_PLAYING_ENTRY] =
- g_signal_new ("notify-playing-entry",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- 0,
- NULL, NULL,
- g_cclosure_marshal_VOID__BOOLEAN,
- G_TYPE_NONE,
- 1,
- G_TYPE_BOOLEAN);
- /**
- * RBShell::notify-custom:
- * @shell: the #RBShell
- * @timeout: length of time (in seconds) to display the notification
- * @primary: main notification text
- * @secondary: secondary notification text
- * @image_uri: URI for an image to include in the notification (optional)
- * @requested: if %TRUE, the notification was triggered by an explicit user action
- *
- * Emitted when a custom notification should be displayed to the user.
- */
- rb_shell_signals[NOTIFY_CUSTOM] =
- g_signal_new ("notify-custom",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- 0,
- NULL, NULL,
- rb_marshal_VOID__UINT_STRING_STRING_STRING_BOOLEAN,
- G_TYPE_NONE,
- 5,
- G_TYPE_UINT, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN);
- /**
- * RBShell::database-load-complete:
- * @shell: the #RBShell
- *
- * Emitted when the database has been loaded. This is intended to allow
- * DBus clients that start a new instance of the application to wait until
- * a reasonable amount of state has been loaded before making further requests.
- */
- rb_shell_signals[DATABASE_LOAD_COMPLETE] =
- g_signal_new ("database-load-complete",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (RBShellClass, database_load_complete),
- NULL, NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE,
- 0);
+ shell->priv->window = GTK_WIDGET (win);
+ shell->priv->iconified = FALSE;
+ g_signal_connect_object (G_OBJECT (win), "window-state-event",
+ G_CALLBACK (rb_shell_window_state_cb),
+ shell, 0);
- g_type_class_add_private (klass, sizeof (RBShellPrivate));
-}
+ g_signal_connect_object (G_OBJECT (win), "configure-event",
+ G_CALLBACK (rb_shell_window_configure_cb),
+ shell, 0);
-static void
-rb_shell_init (RBShell *shell)
-{
- shell->priv = G_TYPE_INSTANCE_GET_PRIVATE (shell, RB_TYPE_SHELL, RBShellPrivate);
+ /* connect after, so that things can affect behaviour */
+ g_signal_connect_object (G_OBJECT (win), "delete_event",
+ G_CALLBACK (rb_shell_window_delete_cb),
+ shell, G_CONNECT_AFTER);
- rb_user_data_dir ();
+ gtk_widget_add_events (GTK_WIDGET (win), GDK_KEY_PRESS_MASK);
+ g_signal_connect_object (G_OBJECT(win), "key_press_event",
+ G_CALLBACK (rb_shell_key_press_event_cb), shell, 0);
- rb_shell_session_init (shell);
-}
+ rb_debug ("shell: initializing shell services");
-static void
-rb_shell_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- RBShell *shell = RB_SHELL (object);
+ shell->priv->podcast_manager = rb_podcast_manager_new (shell->priv->db);
+ shell->priv->track_transfer_queue = rb_track_transfer_queue_new (shell);
+ shell->priv->ui_manager = gtk_ui_manager_new ();
+ shell->priv->source_ui_merge_id = gtk_ui_manager_new_merge_id (shell->priv->ui_manager);
- switch (prop_id)
- {
- case PROP_NO_REGISTRATION:
- shell->priv->no_registration = g_value_get_boolean (value);
- break;
- case PROP_NO_UPDATE:
- shell->priv->no_update = g_value_get_boolean (value);
- break;
- case PROP_DRY_RUN:
- shell->priv->dry_run = g_value_get_boolean (value);
- if (shell->priv->dry_run)
- shell->priv->no_registration = TRUE;
- break;
- case PROP_RHYTHMDB_FILE:
- g_free (shell->priv->rhythmdb_file);
- shell->priv->rhythmdb_file = g_value_dup_string (value);
- break;
- case PROP_PLAYLISTS_FILE:
- g_free (shell->priv->playlists_file);
- shell->priv->playlists_file = g_value_dup_string (value);
- break;
- case PROP_VISIBILITY:
- rb_shell_set_visibility (shell, FALSE, g_value_get_boolean (value));
- break;
- case PROP_AUTOSTARTED:
- shell->priv->autostarted = g_value_get_boolean (value);
- break;
- case PROP_DISABLE_PLUGINS:
- shell->priv->disable_plugins = g_value_get_boolean (value);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-rb_shell_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
-{
- RBShell *shell = RB_SHELL (object);
-
- switch (prop_id)
- {
- case PROP_NO_REGISTRATION:
- g_value_set_boolean (value, shell->priv->no_registration);
- break;
- case PROP_NO_UPDATE:
- g_value_set_boolean (value, shell->priv->no_update);
- break;
- case PROP_DRY_RUN:
- g_value_set_boolean (value, shell->priv->dry_run);
- break;
- case PROP_RHYTHMDB_FILE:
- g_value_set_string (value, shell->priv->rhythmdb_file);
- break;
- case PROP_PLAYLISTS_FILE:
- g_value_set_string (value, shell->priv->playlists_file);
- break;
- case PROP_DB:
- g_value_set_object (value, shell->priv->db);
- break;
- case PROP_UI_MANAGER:
- g_value_set_object (value, shell->priv->ui_manager);
- break;
- case PROP_CLIPBOARD:
- g_value_set_object (value, shell->priv->clipboard_shell);
- break;
- case PROP_PLAYLIST_MANAGER:
- g_value_set_object (value, shell->priv->playlist_manager);
- break;
- case PROP_SHELL_PLAYER:
- g_value_set_object (value, shell->priv->player_shell);
- break;
- case PROP_REMOVABLE_MEDIA_MANAGER:
- g_value_set_object (value, shell->priv->removable_media_manager);
- break;
- case PROP_SELECTED_PAGE:
- g_value_set_object (value, shell->priv->selected_page);
- break;
- case PROP_WINDOW:
- g_value_set_object (value, shell->priv->window);
- break;
- case PROP_PREFS:
- /* create the preferences window the first time we need it */
- if (shell->priv->prefs == NULL) {
- GtkWidget *content;
+ shell->priv->player_shell = rb_shell_player_new (shell->priv->db,
+ shell->priv->ui_manager,
+ shell->priv->actiongroup);
+ g_signal_connect_object (G_OBJECT (shell->priv->player_shell),
+ "playing-source-changed",
+ G_CALLBACK (rb_shell_playing_source_changed_cb),
+ shell, 0);
+ g_signal_connect_object (G_OBJECT (shell->priv->player_shell),
+ "notify::playing-from-queue",
+ G_CALLBACK (rb_shell_playing_from_queue_cb),
+ shell, 0);
+ g_signal_connect_object (G_OBJECT (shell->priv->player_shell),
+ "window_title_changed",
+ G_CALLBACK (rb_shell_player_window_title_changed_cb),
+ shell, 0);
+ shell->priv->clipboard_shell = rb_shell_clipboard_new (shell->priv->actiongroup,
+ shell->priv->ui_manager,
+ shell->priv->db);
+ shell->priv->source_header = rb_source_header_new (shell->priv->ui_manager,
+ shell->priv->actiongroup);
+ gtk_widget_show_all (GTK_WIDGET (shell->priv->source_header));
- shell->priv->prefs = rb_shell_preferences_new (shell->priv->sources);
+ shell->priv->display_page_tree = rb_display_page_tree_new (shell);
+ gtk_widget_show_all (GTK_WIDGET (shell->priv->display_page_tree));
+ g_signal_connect_object (shell->priv->display_page_tree, "drop-received",
+ G_CALLBACK (display_page_tree_drag_received_cb), shell, 0);
+ g_object_get (shell->priv->display_page_tree, "model", &shell->priv->display_page_model, NULL);
+ rb_display_page_group_add_core_groups (G_OBJECT (shell), shell->priv->display_page_model);
- gtk_window_set_transient_for (GTK_WINDOW (shell->priv->prefs),
- GTK_WINDOW (shell->priv->window));
- content = gtk_dialog_get_content_area (GTK_DIALOG (shell->priv->prefs));
- gtk_widget_show_all (content);
- }
- g_value_set_object (value, shell->priv->prefs);
- break;
- case PROP_QUEUE_SOURCE:
- g_value_set_object (value, shell->priv->queue_source);
- break;
- case PROP_LIBRARY_SOURCE:
- g_value_set_object (value, shell->priv->library_source);
- break;
- case PROP_DISPLAY_PAGE_MODEL:
- g_value_set_object (value, shell->priv->display_page_model);
- break;
- case PROP_DISPLAY_PAGE_TREE:
- g_value_set_object (value, shell->priv->display_page_tree);
- break;
- case PROP_VISIBILITY:
- g_value_set_boolean (value, rb_shell_get_visibility (shell));
- break;
- case PROP_SOURCE_HEADER:
- g_value_set_object (value, shell->priv->source_header);
- break;
- case PROP_TRACK_TRANSFER_QUEUE:
- g_value_set_object (value, shell->priv->track_transfer_queue);
- break;
- case PROP_AUTOSTARTED:
- g_value_set_boolean (value, shell->priv->autostarted);
- break;
- case PROP_DISABLE_PLUGINS:
- g_value_set_boolean (value, shell->priv->disable_plugins);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
+ shell->priv->statusbar = rb_statusbar_new (shell->priv->db,
+ shell->priv->ui_manager,
+ shell->priv->track_transfer_queue);
+ g_object_set (shell->priv->player_shell, "statusbar", shell->priv->statusbar, NULL);
+ gtk_widget_show (GTK_WIDGET (shell->priv->statusbar));
-static gboolean
-rb_shell_sync_state (RBShell *shell)
-{
- if (shell->priv->dry_run) {
- rb_debug ("in dry-run mode, not syncing state");
- return FALSE;
- }
+ g_signal_connect_object (shell->priv->display_page_tree, "selected",
+ G_CALLBACK (display_page_selected_cb), shell, 0);
- if (!shell->priv->load_complete) {
- rb_debug ("load incomplete, not syncing state");
- return FALSE;
- }
+ shell->priv->notebook = gtk_notebook_new ();
+ gtk_widget_show (shell->priv->notebook);
+ gtk_notebook_set_show_tabs (GTK_NOTEBOOK (shell->priv->notebook), FALSE);
+ gtk_notebook_set_show_border (GTK_NOTEBOOK (shell->priv->notebook), FALSE);
+ g_signal_connect_object (shell->priv->display_page_tree,
+ "size-allocate",
+ G_CALLBACK (paned_size_allocate_cb),
+ shell, 0);
- rb_debug ("saving playlists");
- rb_playlist_manager_save_playlists (shell->priv->playlist_manager,
- TRUE);
+ shell->priv->queue_source = RB_PLAYLIST_SOURCE (rb_play_queue_source_new (shell));
+ g_object_set (shell->priv->player_shell, "queue-source", shell->priv->queue_source, NULL);
+ g_object_set (shell->priv->clipboard_shell, "queue-source", shell->priv->queue_source, NULL);
+ rb_shell_append_display_page (shell, RB_DISPLAY_PAGE (shell->priv->queue_source), RB_DISPLAY_PAGE_GROUP_LIBRARY);
+ g_object_get (shell->priv->queue_source, "sidebar", &shell->priv->queue_sidebar, NULL);
+ gtk_widget_show_all (shell->priv->queue_sidebar);
+ gtk_widget_set_no_show_all (shell->priv->queue_sidebar, TRUE);
- rb_debug ("saving db");
- rhythmdb_save (shell->priv->db);
- return FALSE;
-}
+ /* places for plugins to put UI */
+ shell->priv->top_container = GTK_BOX (gtk_vbox_new (FALSE, 0));
+ shell->priv->bottom_container = GTK_BOX (gtk_vbox_new (FALSE, 0));
+ shell->priv->sidebar_container = GTK_BOX (gtk_vbox_new (FALSE, 0));
+ shell->priv->right_sidebar_container = GTK_BOX (gtk_vbox_new (FALSE, 0));
-static gboolean
-idle_save_rhythmdb (RBShell *shell)
-{
- rhythmdb_save (shell->priv->db);
+ /* set up sidebars */
+ shell->priv->paned = gtk_hpaned_new ();
+ shell->priv->right_paned = gtk_hpaned_new ();
+ gtk_widget_show_all (shell->priv->right_paned);
+ g_signal_connect_object (G_OBJECT (shell->priv->right_paned),
+ "size-allocate",
+ G_CALLBACK (paned_size_allocate_cb),
+ shell, 0);
+ gtk_widget_set_no_show_all (shell->priv->right_paned, TRUE);
+ {
+ GtkWidget *vbox2 = gtk_vbox_new (FALSE, 0);
- shell->priv->save_db_id = 0;
+ shell->priv->queue_paned = gtk_vpaned_new ();
+ gtk_paned_pack1 (GTK_PANED (shell->priv->queue_paned),
+ GTK_WIDGET (shell->priv->display_page_tree),
+ FALSE, TRUE);
+ gtk_paned_pack2 (GTK_PANED (shell->priv->queue_paned),
+ shell->priv->queue_sidebar,
+ TRUE, TRUE);
+ gtk_container_child_set (GTK_CONTAINER (shell->priv->queue_paned),
+ GTK_WIDGET (shell->priv->display_page_tree),
+ "resize", FALSE,
+ NULL);
- return FALSE;
-}
+ gtk_box_pack_start (GTK_BOX (vbox2),
+ GTK_WIDGET (shell->priv->source_header),
+ FALSE, FALSE, 3);
+ gtk_box_pack_start (GTK_BOX (vbox2),
+ shell->priv->notebook,
+ TRUE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (vbox2),
+ GTK_WIDGET (shell->priv->bottom_container),
+ FALSE, FALSE, 0);
-static gboolean
-idle_save_playlist_manager (RBShell *shell)
-{
- GDK_THREADS_ENTER ();
- rb_playlist_manager_save_playlists (shell->priv->playlist_manager,
- FALSE);
- GDK_THREADS_LEAVE ();
+ gtk_paned_pack1 (GTK_PANED (shell->priv->right_paned),
+ vbox2, TRUE, TRUE);
+ gtk_paned_pack2 (GTK_PANED (shell->priv->right_paned),
+ GTK_WIDGET (shell->priv->right_sidebar_container),
+ FALSE, FALSE);
+ gtk_widget_hide (GTK_WIDGET(shell->priv->right_sidebar_container));
- return TRUE;
-}
+ gtk_box_pack_start (shell->priv->sidebar_container,
+ shell->priv->queue_paned,
+ TRUE, TRUE, 0);
+ gtk_paned_pack1 (GTK_PANED (shell->priv->paned),
+ GTK_WIDGET (shell->priv->sidebar_container),
+ FALSE, TRUE);
+ gtk_paned_pack2 (GTK_PANED (shell->priv->paned),
+ shell->priv->right_paned,
+ TRUE, TRUE);
+ gtk_widget_show (vbox2);
+ }
-static void
-rb_shell_shutdown (RBShell *shell)
-{
- GdkDisplay *display;
+ g_signal_connect_object (G_OBJECT (shell->priv->queue_paned),
+ "size-allocate",
+ G_CALLBACK (paned_size_allocate_cb),
+ shell, 0);
+ gtk_widget_show (shell->priv->paned);
- if (shell->priv->shutting_down)
- return;
- shell->priv->shutting_down = TRUE;
+ shell->priv->main_vbox = gtk_vbox_new (FALSE, 0);
+ gtk_container_set_border_width (GTK_CONTAINER (shell->priv->main_vbox), 0);
+ gtk_box_pack_start (GTK_BOX (shell->priv->main_vbox), GTK_WIDGET (shell->priv->player_shell), FALSE, TRUE, 6);
+ gtk_widget_show (GTK_WIDGET (shell->priv->player_shell));
- /* Hide the main window and tray icon as soon as possible */
- display = gtk_widget_get_display (shell->priv->window);
- gtk_widget_hide (shell->priv->window);
- gdk_display_sync (display);
+ gtk_box_pack_start (GTK_BOX (shell->priv->main_vbox), GTK_WIDGET (shell->priv->top_container), FALSE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (shell->priv->main_vbox), shell->priv->paned, TRUE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (shell->priv->main_vbox), GTK_WIDGET (shell->priv->statusbar), FALSE, TRUE, 0);
+ gtk_widget_show_all (shell->priv->main_vbox);
- if (shell->priv->plugin_engine != NULL) {
- g_object_unref (shell->priv->plugin_engine);
- shell->priv->plugin_engine = NULL;
- }
- if (shell->priv->activatable != NULL) {
- g_object_unref (shell->priv->activatable);
- shell->priv->activatable = NULL;
- }
- if (shell->priv->plugin_settings != NULL) {
- g_object_unref (shell->priv->plugin_settings);
- shell->priv->plugin_settings = NULL;
- }
+ gtk_container_add (GTK_CONTAINER (win), shell->priv->main_vbox);
+
+ rb_profile_end ("constructing widgets");
}
static void
-rb_shell_finalize (GObject *object)
+construct_sources (RBShell *shell)
{
- RBShell *shell = RB_SHELL (object);
+ RBDisplayPage *page_group;
+ char *pathname;
- rb_debug ("Finalizing shell");
+ rb_profile_start ("constructing sources");
- rb_shell_player_stop (shell->priv->player_shell);
+ page_group = RB_DISPLAY_PAGE_GROUP_LIBRARY;
+ shell->priv->library_source = RB_LIBRARY_SOURCE (rb_library_source_new (shell));
+ shell->priv->podcast_source = RB_PODCAST_SOURCE (rb_podcast_main_source_new (shell, shell->priv->podcast_manager));
+ shell->priv->missing_files_source = rb_missing_files_source_new (shell, shell->priv->library_source);
- if (shell->priv->settings != NULL) {
- rb_settings_delayed_sync (shell->priv->settings, NULL, NULL, NULL);
- g_object_unref (shell->priv->settings);
- }
+ shell->priv->import_errors_source = rb_import_errors_source_new (shell,
+ RHYTHMDB_ENTRY_TYPE_IMPORT_ERROR,
+ RHYTHMDB_ENTRY_TYPE_SONG,
+ RHYTHMDB_ENTRY_TYPE_IGNORE);
- g_free (shell->priv->cached_title);
+ rb_shell_append_display_page (shell, RB_DISPLAY_PAGE (shell->priv->library_source), page_group);
+ rb_shell_append_display_page (shell, RB_DISPLAY_PAGE (shell->priv->podcast_source), page_group);
+ rb_shell_append_display_page (shell, RB_DISPLAY_PAGE (shell->priv->missing_files_source), page_group);
+ rb_shell_append_display_page (shell, RB_DISPLAY_PAGE (shell->priv->import_errors_source), page_group);
- if (shell->priv->save_playlist_id > 0) {
- g_source_remove (shell->priv->save_playlist_id);
- shell->priv->save_playlist_id = 0;
- }
+ rb_podcast_main_source_add_subsources (RB_PODCAST_MAIN_SOURCE (shell->priv->podcast_source));
- if (shell->priv->save_db_id > 0) {
- g_source_remove (shell->priv->save_db_id);
- shell->priv->save_db_id = 0;
+ /* Find the playlist name if none supplied */
+ if (shell->priv->playlists_file) {
+ pathname = g_strdup (shell->priv->playlists_file);
+ } else {
+ pathname = rb_find_user_data_file ("playlists.xml");
}
- if (shell->priv->queue_sidebar != NULL) {
- g_object_unref (shell->priv->queue_sidebar);
- }
+ /* Initialize playlist manager */
+ rb_debug ("shell: creating playlist manager");
+ shell->priv->playlist_manager = rb_playlist_manager_new (shell,
+ shell->priv->display_page_model,
+ shell->priv->display_page_tree,
+ pathname);
+
+ g_object_set (shell->priv->clipboard_shell,
+ "playlist-manager", shell->priv->playlist_manager,
+ NULL);
+
+ g_signal_connect_object (G_OBJECT (shell->priv->playlist_manager), "playlist_added",
+ G_CALLBACK (rb_shell_playlist_added_cb), shell, 0);
+ g_signal_connect_object (G_OBJECT (shell->priv->playlist_manager), "playlist_created",
+ G_CALLBACK (rb_shell_playlist_created_cb), shell, 0);
- rb_debug ("shutting down playlist manager");
- rb_playlist_manager_shutdown (shell->priv->playlist_manager);
+ /* Initialize removable media manager */
+ rb_debug ("shell: creating removable media manager");
+ shell->priv->removable_media_manager = rb_removable_media_manager_new (shell);
- rb_debug ("unreffing playlist manager");
- g_object_unref (shell->priv->playlist_manager);
+ g_signal_connect_object (G_OBJECT (shell->priv->removable_media_manager), "medium_added",
+ G_CALLBACK (rb_shell_medium_added_cb), shell, 0);
- rb_debug ("unreffing removable media manager");
- g_object_unref (shell->priv->removable_media_manager);
- g_object_unref (shell->priv->track_transfer_queue);
- rb_debug ("unreffing podcast manager");
- g_object_unref (shell->priv->podcast_manager);
+ g_free (pathname);
- rb_debug ("unreffing clipboard shell");
- g_object_unref (shell->priv->clipboard_shell);
+ rb_profile_end ("constructing sources");
+}
- rb_debug ("destroying prefs");
- if (shell->priv->prefs != NULL)
- gtk_widget_destroy (shell->priv->prefs);
+static void
+construct_load_ui (RBShell *shell)
+{
+ GtkWidget *menubar;
+ GtkWidget *toolbar;
+ GtkToolItem *tool_item;
+ GError *error = NULL;
- g_free (shell->priv->rhythmdb_file);
+ rb_debug ("shell: loading ui");
+ rb_profile_start ("loading ui");
- g_free (shell->priv->playlists_file);
+ gtk_ui_manager_insert_action_group (shell->priv->ui_manager,
+ shell->priv->actiongroup, 0);
+ gtk_ui_manager_add_ui_from_file (shell->priv->ui_manager,
+ rb_file ("rhythmbox-ui.xml"), &error);
- rb_debug ("destroying window");
- gtk_widget_destroy (shell->priv->window);
+ gtk_ui_manager_ensure_update (shell->priv->ui_manager);
+ gtk_window_add_accel_group (GTK_WINDOW (shell->priv->window),
+ gtk_ui_manager_get_accel_group (shell->priv->ui_manager));
+ menubar = gtk_ui_manager_get_widget (shell->priv->ui_manager, "/MenuBar");
- g_list_free (shell->priv->sources);
- shell->priv->sources = NULL;
+ gtk_box_pack_start (GTK_BOX (shell->priv->main_vbox), menubar, FALSE, FALSE, 0);
+ gtk_box_reorder_child (GTK_BOX (shell->priv->main_vbox), menubar, 0);
+
+ toolbar = gtk_ui_manager_get_widget (shell->priv->ui_manager, "/ToolBar");
+ gtk_style_context_add_class (gtk_widget_get_style_context (toolbar),
+ GTK_STYLE_CLASS_PRIMARY_TOOLBAR);
+ g_settings_bind (shell->priv->settings, "toolbar-visible",
+ toolbar, "visible",
+ G_SETTINGS_BIND_DEFAULT);
+ gtk_box_pack_start (GTK_BOX (shell->priv->main_vbox), toolbar, FALSE, FALSE, 0);
+ gtk_box_reorder_child (GTK_BOX (shell->priv->main_vbox), toolbar, 1);
- g_hash_table_destroy (shell->priv->sources_hash);
+ shell->priv->volume_button = gtk_volume_button_new ();
+ g_signal_connect (shell->priv->volume_button, "value-changed",
+ G_CALLBACK (rb_shell_volume_widget_changed_cb),
+ shell);
+ g_signal_connect (shell->priv->player_shell, "notify::volume",
+ G_CALLBACK (rb_shell_player_volume_changed_cb),
+ shell);
+ rb_shell_player_volume_changed_cb (shell->priv->player_shell, NULL, shell);
- rb_debug ("shutting down DB");
- rhythmdb_shutdown (shell->priv->db);
+ tool_item = gtk_tool_item_new ();
+ gtk_tool_item_set_expand (tool_item, TRUE);
+ gtk_widget_show (GTK_WIDGET (tool_item));
+ gtk_toolbar_insert (GTK_TOOLBAR (toolbar), tool_item, -1);
- rb_debug ("unreffing DB");
- g_object_unref (shell->priv->db);
+ tool_item = gtk_tool_item_new ();
+ gtk_container_add (GTK_CONTAINER (tool_item), shell->priv->volume_button);
+ gtk_widget_show_all (GTK_WIDGET (tool_item));
+ gtk_toolbar_insert (GTK_TOOLBAR (toolbar), tool_item, -1);
- G_OBJECT_CLASS (rb_shell_parent_class)->finalize (object);
+ gtk_widget_set_tooltip_text (shell->priv->volume_button,
+ _("Change the music volume"));
- rb_debug ("shell shutdown complete");
+ if (error != NULL) {
+ g_warning ("Couldn't merge %s: %s",
+ rb_file ("rhythmbox-ui.xml"), error->message);
+ g_clear_error (&error);
+ }
+
+ rb_profile_end ("loading ui");
}
-/**
- * rb_shell_new:
- * @no_registration: if %TRUE, single-instance features are disabled
- * @no_update: if %TRUE, don't update the database file
- * @dry_run: if %TRUE, don't write back file metadata changes
- * @autostarted: %TRUE if autostarted by the session manager
- * @disable_plugins: %TRUE if the plugins should be disabled
- * @rhythmdb: path to the database file
- * @playlists: path to the playlist file
- *
- * Creates the Rhythmbox shell. This is effectively a singleton, so it doesn't
- * make sense to call this from anywhere other than main.c.
- *
- * Return value: the #RBShell instance
- */
-RBShell *
-rb_shell_new (gboolean no_registration,
- gboolean no_update,
- gboolean dry_run,
- gboolean autostarted,
- gboolean disable_plugins,
- char *rhythmdb,
- char *playlists)
+static void
+extension_added_cb (PeasExtensionSet *set, PeasPluginInfo *info, PeasExtension *extension, RBShell *shell)
{
- return g_object_new (RB_TYPE_SHELL,
- "no-registration", no_registration,
- "no-update", no_update,
- "dry-run", dry_run, "rhythmdb-file", rhythmdb,
- "playlists-file", playlists,
- "autostarted", autostarted,
- "disable-plugins", disable_plugins,
- NULL);
+ rb_debug ("activating extension %s", peas_plugin_info_get_name (info));
+ peas_extension_call (extension, "activate");
}
-static GMountOperation *
-rb_shell_create_mount_op_cb (RhythmDB *db, RBShell *shell)
+static void
+extension_removed_cb (PeasExtensionSet *set, PeasPluginInfo *info, PeasExtension *extension, RBShell *shell)
{
- /* we don't want the operation to be modal, so we don't associate it with the window. */
- GMountOperation *op = gtk_mount_operation_new (NULL);
- gtk_mount_operation_set_screen (GTK_MOUNT_OPERATION (op),
- gtk_window_get_screen (GTK_WINDOW (shell->priv->window)));
- return op;
+ rb_debug ("deactivating extension %s", peas_plugin_info_get_name (info));
+ peas_extension_call (extension, "deactivate");
}
static void
-construct_db (RBShell *shell)
+construct_plugins (RBShell *shell)
{
- char *pathname;
-
- /* Initialize the database */
- rb_debug ("creating database object");
- rb_profile_start ("creating database object");
+ char *typelib_dir;
+ char *plugindir;
+ char *plugindatadir;
+ const GList *plugins;
+ const GList *l;
+ GError *error = NULL;
- if (shell->priv->rhythmdb_file) {
- pathname = g_strdup (shell->priv->rhythmdb_file);
- } else {
- pathname = rb_find_user_data_file ("rhythmdb.xml");
+ if (shell->priv->disable_plugins) {
+ return;
}
-#ifdef WITH_RHYTHMDB_TREE
- shell->priv->db = rhythmdb_tree_new (pathname);
-#elif defined(WITH_RHYTHMDB_GDA)
- shell->priv->db = rhythmdb_gda_new (pathname);
-#endif
- g_free (pathname);
+ rb_profile_start ("loading plugins");
+ shell->priv->plugin_settings = g_settings_new ("org.gnome.rhythmbox.plugins");
- if (shell->priv->dry_run)
- g_object_set (shell->priv->db, "dry-run", TRUE, NULL);
- if (shell->priv->no_update)
- g_object_set (shell->priv->db, "no-update", TRUE, NULL);
+ shell->priv->plugin_engine = peas_engine_new ();
+ /* need an #ifdef for this? */
+ peas_engine_enable_loader (shell->priv->plugin_engine, "python");
- g_signal_connect_object (G_OBJECT (shell->priv->db), "load-complete",
- G_CALLBACK (rb_shell_load_complete_cb), shell,
- 0);
- g_signal_connect_object (G_OBJECT (shell->priv->db), "create-mount-op",
- G_CALLBACK (rb_shell_create_mount_op_cb), shell,
- 0);
+ typelib_dir = g_build_filename (LIBDIR,
+ "girepository-1.0",
+ NULL);
+ if (g_irepository_require_private (g_irepository_get_default (),
+ typelib_dir, "MPID", "3.0", 0, &error) == FALSE) {
+ g_clear_error (&error);
+ if (g_irepository_require (g_irepository_get_default (), "MPID", "3.0", 0, &error) == FALSE) {
+ g_warning ("Could not load MPID typelib: %s", error->message);
+ g_clear_error (&error);
+ }
+ }
- rb_profile_end ("creating database object");
-}
+ if (g_irepository_require_private (g_irepository_get_default (),
+ typelib_dir, "RB", "3.0", 0, &error) == FALSE) {
+ g_clear_error (&error);
+ if (g_irepository_require (g_irepository_get_default (), "RB", "3.0", 0, &error) == FALSE) {
+ g_warning ("Could not load RB typelib: %s", error->message);
+ g_clear_error (&error);
+ }
+ }
+ g_free (typelib_dir);
-static void
-construct_widgets (RBShell *shell)
-{
- GtkWindow *win;
+ if (g_irepository_require (g_irepository_get_default (), "Peas", "1.0", 0, &error) == FALSE) {
+ g_warning ("Could not load Peas typelib: %s", error->message);
+ g_clear_error (&error);
+ }
- rb_profile_start ("constructing widgets");
+ if (g_irepository_require (g_irepository_get_default (), "PeasGtk", "1.0", 0, &error) == FALSE) {
+ g_warning ("Could not load PeasGtk typelib: %s", error->message);
+ g_clear_error (&error);
+ }
- /* initialize UI */
- win = GTK_WINDOW (gtk_window_new (GTK_WINDOW_TOPLEVEL));
- gtk_window_set_title (win, _("Rhythmbox"));
+ plugindir = g_build_filename (rb_user_data_dir (), "plugins", NULL);
+ rb_debug ("plugin search path: %s", plugindir);
+ peas_engine_add_search_path (shell->priv->plugin_engine,
+ plugindir,
+ plugindir);
+ g_free (plugindir);
- shell->priv->window = GTK_WIDGET (win);
- shell->priv->iconified = FALSE;
- g_signal_connect_object (G_OBJECT (win), "window-state-event",
- G_CALLBACK (rb_shell_window_state_cb),
- shell, 0);
+ plugindir = g_build_filename (LIBDIR, "rhythmbox", "plugins", NULL);
+ plugindatadir = g_build_filename (DATADIR, "rhythmbox", "plugins", NULL);
+ rb_debug ("plugin search path: %s / %s", plugindir, plugindatadir);
+ peas_engine_add_search_path (shell->priv->plugin_engine,
+ plugindir,
+ plugindatadir);
+ g_free (plugindir);
+ g_free (plugindatadir);
- g_signal_connect_object (G_OBJECT (win), "configure-event",
- G_CALLBACK (rb_shell_window_configure_cb),
- shell, 0);
+#ifdef USE_UNINSTALLED_DIRS
+ plugindir = g_build_filename (SHARE_UNINSTALLED_BUILDDIR, "..", UNINSTALLED_PLUGINS_LOCATION, NULL);
+ rb_debug ("plugin search path: %s", plugindir);
+ peas_engine_add_search_path (shell->priv->plugin_engine,
+ plugindir,
+ plugindir);
+ g_free (plugindir);
+#endif
- /* connect after, so that things can affect behaviour */
- g_signal_connect_object (G_OBJECT (win), "delete_event",
- G_CALLBACK (rb_shell_window_delete_cb),
- shell, G_CONNECT_AFTER);
+ shell->priv->activatable = peas_extension_set_new (shell->priv->plugin_engine,
+ PEAS_TYPE_ACTIVATABLE,
+ "object", shell,
+ NULL);
+ g_signal_connect (shell->priv->activatable, "extension-added", G_CALLBACK (extension_added_cb), shell);
+ g_signal_connect (shell->priv->activatable, "extension-removed", G_CALLBACK (extension_removed_cb), shell);
- gtk_widget_add_events (GTK_WIDGET (win), GDK_KEY_PRESS_MASK);
- g_signal_connect_object (G_OBJECT(win), "key_press_event",
- G_CALLBACK (rb_shell_key_press_event_cb), shell, 0);
+ g_settings_bind (shell->priv->plugin_settings,
+ "active-plugins",
+ shell->priv->plugin_engine,
+ "loaded-plugins",
+ G_SETTINGS_BIND_DEFAULT);
- rb_debug ("shell: initializing shell services");
+ /* load builtin plugins */
+ plugins = peas_engine_get_plugin_list (shell->priv->plugin_engine);
+ for (l = plugins; l != NULL; l = l->next) {
+ PeasPluginInfo *info = PEAS_PLUGIN_INFO (l->data);
+ if (peas_plugin_info_is_builtin (info) &&
+ g_strcmp0 (peas_plugin_info_get_module_name (info), "rb") != 0) {
+ peas_engine_load_plugin (shell->priv->plugin_engine, info);
+ }
+ }
- shell->priv->podcast_manager = rb_podcast_manager_new (shell->priv->db);
- shell->priv->track_transfer_queue = rb_track_transfer_queue_new (shell);
- shell->priv->ui_manager = gtk_ui_manager_new ();
- shell->priv->source_ui_merge_id = gtk_ui_manager_new_merge_id (shell->priv->ui_manager);
+ rb_profile_end ("loading plugins");
+}
- shell->priv->player_shell = rb_shell_player_new (shell->priv->db,
- shell->priv->ui_manager,
- shell->priv->actiongroup);
- g_signal_connect_object (G_OBJECT (shell->priv->player_shell),
- "playing-source-changed",
- G_CALLBACK (rb_shell_playing_source_changed_cb),
- shell, 0);
- g_signal_connect_object (G_OBJECT (shell->priv->player_shell),
- "notify::playing-from-queue",
- G_CALLBACK (rb_shell_playing_from_queue_cb),
- shell, 0);
- g_signal_connect_object (G_OBJECT (shell->priv->player_shell),
- "window_title_changed",
- G_CALLBACK (rb_shell_player_window_title_changed_cb),
- shell, 0);
- shell->priv->clipboard_shell = rb_shell_clipboard_new (shell->priv->actiongroup,
- shell->priv->ui_manager,
- shell->priv->db);
- shell->priv->source_header = rb_source_header_new (shell->priv->ui_manager,
- shell->priv->actiongroup);
- gtk_widget_show_all (GTK_WIDGET (shell->priv->source_header));
+static void
+emit_action_state_update (RBShell *shell, const char *action)
+{
+ GDBusConnection *bus;
+ GVariant *state;
+
+
+ bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
+
+ state = g_action_group_get_action_state (G_ACTION_GROUP (shell), action);
+ g_signal_emit_by_name (shell, "action-state-changed::LoadURI", "LoadURI", state);
+ if (bus != NULL) {
+ g_dbus_connection_emit_signal (bus,
+ NULL,
+ "/org/gnome/Rhythmbox3",
+ "org.gtk.Actions",
+ "StateChanged",
+ g_variant_new ("(sv)", action, state),
+ NULL);
+ g_object_unref (bus);
+ }
+ g_variant_unref (state);
+}
+
+static gboolean
+_scan_idle (RBShell *shell)
+{
+ gboolean loaded, scanned;
+
+ GDK_THREADS_ENTER ();
+ rb_removable_media_manager_scan (shell->priv->removable_media_manager);
+ GDK_THREADS_LEAVE ();
+
+ if (shell->priv->no_registration == FALSE) {
+ g_variant_get (g_action_group_get_action_state (G_ACTION_GROUP (shell), "LoadURI"), "(bb)", &loaded, &scanned);
+ g_action_group_change_action_state (G_ACTION_GROUP (shell), "LoadURI", g_variant_new ("(bb)", loaded, TRUE));
+ emit_action_state_update (shell, "LoadURI");
+ }
+
+ return FALSE;
+}
+
+static void
+rb_shell_startup (GApplication *app)
+{
+ RBShell *shell = RB_SHELL (app);
+ GtkAction *gtkaction;
+
+ rb_debug ("Constructing shell");
+ rb_profile_start ("constructing shell");
+
+ g_signal_connect_object (shell->priv->settings, "changed", G_CALLBACK (settings_changed_cb), shell, 0);
+
+ gtkaction = gtk_action_group_get_action (shell->priv->actiongroup, "ViewSidePane");
+ g_settings_bind (shell->priv->settings, "display-page-tree-visible",
+ gtkaction, "active",
+ G_SETTINGS_BIND_DEFAULT);
+ g_settings_bind (shell->priv->settings, "display-page-tree-visible",
+ shell->priv->sidebar_container, "visible",
+ G_SETTINGS_BIND_DEFAULT);
+
+ gtkaction = gtk_action_group_get_action (shell->priv->actiongroup, "ViewToolbar");
+ g_settings_bind (shell->priv->settings, "toolbar-visible",
+ gtkaction, "active",
+ G_SETTINGS_BIND_DEFAULT);
+
+ rb_debug ("shell: syncing with settings");
+ rb_shell_sync_pane_visibility (shell);
+
+ g_signal_connect_object (G_OBJECT (shell->priv->db), "save-error",
+ G_CALLBACK (rb_shell_db_save_error_cb), shell, 0);
+
+ construct_sources (shell);
+
+ construct_load_ui (shell);
+
+ construct_plugins (shell);
+
+ rb_shell_sync_window_state (shell, FALSE);
+ rb_shell_sync_smalldisplay (shell);
+ rb_shell_sync_party_mode (shell);
+ rb_shell_sync_toolbar_state (shell);
+
+ rb_shell_select_page (shell, RB_DISPLAY_PAGE (shell->priv->library_source));
+
+ /* by now we've added the built in sources and any sources from plugins,
+ * so we can consider the fixed page groups loaded
+ */
+ rb_display_page_group_loaded (RB_DISPLAY_PAGE_GROUP (RB_DISPLAY_PAGE_GROUP_LIBRARY));
+ rb_display_page_group_loaded (RB_DISPLAY_PAGE_GROUP (RB_DISPLAY_PAGE_GROUP_STORES));
+
+ rb_missing_plugins_init (GTK_WINDOW (shell->priv->window));
+
+ g_idle_add ((GSourceFunc)_scan_idle, shell);
+
+ /* GO GO GO! */
+ rb_debug ("loading database");
+ rhythmdb_load (shell->priv->db);
+
+ rb_debug ("shell: syncing window state");
+ rb_shell_sync_paned (shell);
+
+ /* set initial visibility */
+ rb_shell_set_visibility (shell, TRUE, TRUE);
+
+ gdk_notify_startup_complete ();
+
+ /* focus play if small, the entry view if not */
+ if (g_settings_get_boolean (shell->priv->settings, "small-display")) {
+ GtkWidget *play_button;
+
+ play_button = gtk_ui_manager_get_widget (shell->priv->ui_manager, "/ToolBar/Play");
+ gtk_widget_grab_focus (play_button);
+ } else {
+ RBEntryView *view;
+
+ view = rb_source_get_entry_view (RB_SOURCE (shell->priv->library_source));
+ if (view != NULL) {
+ gtk_widget_grab_focus (GTK_WIDGET (view));
+ }
+ }
+
+ rb_profile_end ("constructing shell");
+
+ /* window-based usage counting doesn't work for us, just hold the app until
+ * we're asked to quit.
+ */
+ g_application_hold (app);
+}
+
+static gboolean
+rb_shell_local_command_line (GApplication *app, gchar ***args, int *exit_status)
+{
+ RBShell *shell;
+ GError *error = NULL;
+ gboolean scanned;
+ gboolean loaded;
+ GPtrArray *files;
+ int n_files;
+ int i;
+
+ n_files = g_strv_length (*args) - 1;
+
+ shell = RB_SHELL (app);
+ if (shell->priv->no_registration) {
+ if (n_files > 0) {
+ g_warning ("Unable to open files on the commandline with --no-registration");
+ }
+ rb_shell_startup (app);
+ return TRUE;
+ }
+
+ if (!g_application_register (app, NULL, &error)) {
+ g_critical ("%s", error->message);
+ g_error_free (error);
+ *exit_status = 1;
+ return TRUE;
+ }
+
+ if (n_files <= 0) {
+ g_application_activate (app);
+ *exit_status = 0;
+ return TRUE;
+ }
+
+ files = g_ptr_array_new_with_free_func (g_object_unref);
+ for (i = 0; i < n_files; i++) {
+ g_ptr_array_add (files, g_file_new_for_commandline_arg ((*args)[i + 1]));
+ }
+
+ g_variant_get (g_action_group_get_action_state (G_ACTION_GROUP (app), "LoadURI"), "(bb)", &loaded, &scanned);
+ if (loaded) {
+ rb_debug ("opening files immediately");
+ g_application_open (app, (GFile **)files->pdata, files->len, "");
+ g_ptr_array_free (files, TRUE);
+ } else {
+ rb_debug ("opening files once db is loaded");
+ g_signal_connect (app, "action-state-changed::LoadURI", G_CALLBACK (load_state_changed_cb), files);
+ }
+
+ return TRUE;
+}
+static void
+rb_shell_class_init (RBShellClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GApplicationClass *app_class = G_APPLICATION_CLASS (klass);
+
+ object_class->set_property = rb_shell_set_property;
+ object_class->get_property = rb_shell_get_property;
+ object_class->finalize = rb_shell_finalize;
+ object_class->constructed = rb_shell_constructed;
+
+ app_class->activate = rb_shell_activate;
+ app_class->open = rb_shell_open;
+ app_class->local_command_line = rb_shell_local_command_line;
+ app_class->startup = rb_shell_startup;
+
+ klass->visibility_changing = rb_shell_visibility_changing;
+
+ /**
+ * RBShell:no-registration:
+ *
+ * If %TRUE, disable single-instance features.
+ */
+ g_object_class_install_property (object_class,
+ PROP_NO_REGISTRATION,
+ g_param_spec_boolean ("no-registration",
+ "no-registration",
+ "Whether or not to register",
+ FALSE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+ /**
+ * RBShell:no-update:
+ *
+ * If %TRUE, don't update the database.
+ */
+ g_object_class_install_property (object_class,
+ PROP_NO_UPDATE,
+ g_param_spec_boolean ("no-update",
+ "no-update",
+ "Whether or not to update the library",
+ FALSE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+ /**
+ * RBShell:dry-run:
+ *
+ * If TRUE, don't write back file metadata changes.
+ */
+ g_object_class_install_property (object_class,
+ PROP_DRY_RUN,
+ g_param_spec_boolean ("dry-run",
+ "dry-run",
+ "Whether or not this is a dry run",
+ FALSE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+ /**
+ * RBShell:rhythmdb-file:
+ *
+ * The path to the rhythmdb file
+ */
+ g_object_class_install_property (object_class,
+ PROP_RHYTHMDB_FILE,
+ g_param_spec_string ("rhythmdb-file",
+ "rhythmdb-file",
+ "The RhythmDB file to use",
+ "rhythmdb.xml",
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+ /**
+ * RBShell:playlists-file:
+ *
+ * The path to the playlist file
+ */
+ g_object_class_install_property (object_class,
+ PROP_PLAYLISTS_FILE,
+ g_param_spec_string ("playlists-file",
+ "playlists-file",
+ "The playlists file to use",
+ "playlists.xml",
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+ /**
+ * RBShell:selected-page:
+ *
+ * The currently selected display page
+ */
+ g_object_class_install_property (object_class,
+ PROP_SELECTED_PAGE,
+ g_param_spec_object ("selected-page",
+ "selected-page",
+ "Display page which is currently selected",
+ RB_TYPE_DISPLAY_PAGE,
+ G_PARAM_READABLE));
+ /**
+ * RBShell:db:
+ *
+ * The #RhythmDB instance
+ */
+ g_object_class_install_property (object_class,
+ PROP_DB,
+ g_param_spec_object ("db",
+ "RhythmDB",
+ "RhythmDB object",
+ RHYTHMDB_TYPE,
+ G_PARAM_READABLE));
+ /**
+ * RBShell:ui-manager:
+ *
+ * The #GtkUIManager instance
+ */
+ g_object_class_install_property (object_class,
+ PROP_UI_MANAGER,
+ g_param_spec_object ("ui-manager",
+ "GtkUIManager",
+ "GtkUIManager object",
+ GTK_TYPE_UI_MANAGER,
+ G_PARAM_READABLE));
+ /**
+ * RBShell:clipboard:
+ *
+ * The #RBShellClipboard instance
+ */
+ g_object_class_install_property (object_class,
+ PROP_CLIPBOARD,
+ g_param_spec_object ("clipboard",
+ "RBShellClipboard",
+ "RBShellClipboard object",
+ RB_TYPE_SHELL_CLIPBOARD,
+ G_PARAM_READABLE));
+ /**
+ * RBShell:playlist-manager:
+ *
+ * The #RBPlaylistManager instance
+ */
+ g_object_class_install_property (object_class,
+ PROP_PLAYLIST_MANAGER,
+ g_param_spec_object ("playlist-manager",
+ "RBPlaylistManager",
+ "RBPlaylistManager object",
+ RB_TYPE_PLAYLIST_MANAGER,
+ G_PARAM_READABLE));
+ /**
+ * RBShell:shell-player:
+ *
+ * The #RBShellPlayer instance
+ */
+ g_object_class_install_property (object_class,
+ PROP_SHELL_PLAYER,
+ g_param_spec_object ("shell-player",
+ "RBShellPlayer",
+ "RBShellPlayer object",
+ RB_TYPE_SHELL_PLAYER,
+ G_PARAM_READABLE));
+ /**
+ * RBShell:removable-media-manager:
+ *
+ * The #RBRemovableMediaManager instance
+ */
+ g_object_class_install_property (object_class,
+ PROP_REMOVABLE_MEDIA_MANAGER,
+ g_param_spec_object ("removable-media-manager",
+ "RBRemovableMediaManager",
+ "RBRemovableMediaManager object",
+ RB_TYPE_REMOVABLE_MEDIA_MANAGER,
+ G_PARAM_READABLE));
+ /**
+ * RBShell:window:
+ *
+ * The main Rhythmbox window.
+ */
+ g_object_class_install_property (object_class,
+ PROP_WINDOW,
+ g_param_spec_object ("window",
+ "GtkWindow",
+ "GtkWindow object",
+ GTK_TYPE_WINDOW,
+ G_PARAM_READABLE));
+ /**
+ * RBShell:prefs:
+ *
+ * The #RBShellPreferences instance
+ */
+ g_object_class_install_property (object_class,
+ PROP_PREFS,
+ g_param_spec_object ("prefs",
+ "RBShellPreferences",
+ "RBShellPreferences object",
+ RB_TYPE_SHELL_PREFERENCES,
+ G_PARAM_READABLE));
+ /**
+ * RBShell:queue-source:
+ *
+ * The play queue source
+ */
+ g_object_class_install_property (object_class,
+ PROP_QUEUE_SOURCE,
+ g_param_spec_object ("queue-source",
+ "queue-source",
+ "Queue source",
+ RB_TYPE_PLAY_QUEUE_SOURCE,
+ G_PARAM_READABLE));
+ /**
+ * RBShell:library-source:
+ *
+ * The library source
+ */
+ g_object_class_install_property (object_class,
+ PROP_LIBRARY_SOURCE,
+ g_param_spec_object ("library-source",
+ "library-source",
+ "Library source",
+ RB_TYPE_LIBRARY_SOURCE,
+ G_PARAM_READABLE));
+ /**
+ * RBShell:display-page-model:
+ *
+ * The model underlying the display page tree
+ */
+ g_object_class_install_property (object_class,
+ PROP_DISPLAY_PAGE_MODEL,
+ g_param_spec_object ("display-page-model",
+ "display-page-model",
+ "RBDisplayPageModel",
+ RB_TYPE_DISPLAY_PAGE_MODEL,
+ G_PARAM_READABLE));
+
+ /**
+ * RBShell:display-page-tree:
+ *
+ * The #RBDisplayPageTree instance
+ */
+ g_object_class_install_property (object_class,
+ PROP_DISPLAY_PAGE_TREE,
+ g_param_spec_object ("display-page-tree",
+ "display-page-tree",
+ "RBDisplayPageTree",
+ RB_TYPE_DISPLAY_PAGE_TREE,
+ G_PARAM_READABLE));
+
+ /**
+ * RBShell:visibility:
+ *
+ * Whether the main window is currently visible.
+ */
+ g_object_class_install_property (object_class,
+ PROP_VISIBILITY,
+ g_param_spec_boolean ("visibility",
+ "visibility",
+ "Current window visibility",
+ TRUE,
+ G_PARAM_READWRITE));
+ /**
+ * RBShell:source-header:
+ *
+ * The #RBSourceHeader instance
+ */
+ g_object_class_install_property (object_class,
+ PROP_SOURCE_HEADER,
+ g_param_spec_object ("source-header",
+ "source header widget",
+ "RBSourceHeader",
+ RB_TYPE_SOURCE_HEADER,
+ G_PARAM_READABLE));
+
+ /**
+ * RBShell:track-transfer-queue:
+ *
+ * The #RBTrackTransferQueue instance
+ */
+ g_object_class_install_property (object_class,
+ PROP_TRACK_TRANSFER_QUEUE,
+ g_param_spec_object ("track-transfer-queue",
+ "RBTrackTransferQueue",
+ "RBTrackTransferQueue object",
+ RB_TYPE_TRACK_TRANSFER_QUEUE,
+ G_PARAM_READABLE));
+ /**
+ * RBShell:autostarted:
+ *
+ * Whether Rhythmbox was automatically started by the session manager
+ */
+ g_object_class_install_property (object_class,
+ PROP_AUTOSTARTED,
+ g_param_spec_boolean ("autostarted",
+ "autostarted",
+ "TRUE if autostarted",
+ FALSE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+ /**
+ * RBShell:disable-plugins:
+ *
+ * If %TRUE, disable plugins
+ */
+ g_object_class_install_property (object_class,
+ PROP_DISABLE_PLUGINS,
+ g_param_spec_boolean ("disable-plugins",
+ "disable-plugins",
+ "Whether or not to disable plugins",
+ FALSE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+ /**
+ * RBShell::visibility-changed:
+ * @shell: the #RBShell
+ * @visibile: new visibility
+ *
+ * Emitted after the visibility of the main Rhythmbox window has
+ * changed.
+ */
+ rb_shell_signals[VISIBILITY_CHANGED] =
+ g_signal_new ("visibility_changed",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (RBShellClass, visibility_changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__BOOLEAN,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_BOOLEAN);
+ /**
+ * RBShell::visibility-changing:
+ * @shell: the #RBShell
+ * @initial: if %TRUE, this is the initial visibility for the window
+ * @visible: new shell visibility
+ *
+ * Emitted before the visibility of the main window changes. The return
+ * value overrides the visibility setting. If multiple signal handlers
+ * are attached, the last one wins.
+ */
+ rb_shell_signals[VISIBILITY_CHANGING] =
+ g_signal_new ("visibility_changing",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (RBShellClass, visibility_changing),
+ NULL, NULL,
+ rb_marshal_BOOLEAN__BOOLEAN_BOOLEAN,
+ G_TYPE_BOOLEAN,
+ 2,
+ G_TYPE_BOOLEAN,
+ G_TYPE_BOOLEAN);
+
+ /**
+ * RBShell::create-song-info:
+ * @shell: the #RBShell
+ * @song_info: the new #RBSongInfo window
+ * @multi: if %TRUE, the song info window is for multiple entries
+ *
+ * Emitted when creating a new #RBSongInfo window. Signal handlers can
+ * add pages to the song info window notebook to display additional
+ * information.
+ */
+ rb_shell_signals[CREATE_SONG_INFO] =
+ g_signal_new ("create_song_info",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (RBShellClass, create_song_info),
+ NULL, NULL,
+ rb_marshal_VOID__OBJECT_BOOLEAN,
+ G_TYPE_NONE,
+ 2,
+ RB_TYPE_SONG_INFO, G_TYPE_BOOLEAN);
+ /**
+ * RBShell::notify-playing-entry:
+ * @shell: the #RBShell
+ *
+ * Emitted when a notification should be displayed showing the current
+ * playing entry.
+ */
+ rb_shell_signals[NOTIFY_PLAYING_ENTRY] =
+ g_signal_new ("notify-playing-entry",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ g_cclosure_marshal_VOID__BOOLEAN,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_BOOLEAN);
+ /**
+ * RBShell::notify-custom:
+ * @shell: the #RBShell
+ * @timeout: length of time (in seconds) to display the notification
+ * @primary: main notification text
+ * @secondary: secondary notification text
+ * @image_uri: URI for an image to include in the notification (optional)
+ * @requested: if %TRUE, the notification was triggered by an explicit user action
+ *
+ * Emitted when a custom notification should be displayed to the user.
+ */
+ rb_shell_signals[NOTIFY_CUSTOM] =
+ g_signal_new ("notify-custom",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ rb_marshal_VOID__UINT_STRING_STRING_STRING_BOOLEAN,
+ G_TYPE_NONE,
+ 5,
+ G_TYPE_UINT, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN);
+ g_type_class_add_private (klass, sizeof (RBShellPrivate));
+}
- shell->priv->display_page_tree = rb_display_page_tree_new (shell);
- gtk_widget_show_all (GTK_WIDGET (shell->priv->display_page_tree));
- g_signal_connect_object (shell->priv->display_page_tree, "drop-received",
- G_CALLBACK (display_page_tree_drag_received_cb), shell, 0);
- g_object_get (shell->priv->display_page_tree, "model", &shell->priv->display_page_model, NULL);
- rb_display_page_group_add_core_groups (G_OBJECT (shell), shell->priv->display_page_model);
+static void
+rb_shell_init (RBShell *shell)
+{
+ shell->priv = G_TYPE_INSTANCE_GET_PRIVATE (shell, RB_TYPE_SHELL, RBShellPrivate);
- shell->priv->statusbar = rb_statusbar_new (shell->priv->db,
- shell->priv->ui_manager,
- shell->priv->track_transfer_queue);
- g_object_set (shell->priv->player_shell, "statusbar", shell->priv->statusbar, NULL);
- gtk_widget_show (GTK_WIDGET (shell->priv->statusbar));
+ rb_user_data_dir ();
+ rb_refstring_system_init ();
- g_signal_connect_object (shell->priv->display_page_tree, "selected",
- G_CALLBACK (display_page_selected_cb), shell, 0);
+#ifdef USE_UNINSTALLED_DIRS
+ rb_file_helpers_init (TRUE);
+#else
+ rb_file_helpers_init (FALSE);
+#endif
+ rb_stock_icons_init ();
- shell->priv->notebook = gtk_notebook_new ();
- gtk_widget_show (shell->priv->notebook);
- gtk_notebook_set_show_tabs (GTK_NOTEBOOK (shell->priv->notebook), FALSE);
- gtk_notebook_set_show_border (GTK_NOTEBOOK (shell->priv->notebook), FALSE);
- g_signal_connect_object (shell->priv->display_page_tree,
- "size-allocate",
- G_CALLBACK (paned_size_allocate_cb),
- shell, 0);
+ rb_shell_session_init (shell);
- shell->priv->queue_source = RB_PLAYLIST_SOURCE (rb_play_queue_source_new (shell));
- g_object_set (shell->priv->player_shell, "queue-source", shell->priv->queue_source, NULL);
- g_object_set (shell->priv->clipboard_shell, "queue-source", shell->priv->queue_source, NULL);
- rb_shell_append_display_page (shell, RB_DISPLAY_PAGE (shell->priv->queue_source), RB_DISPLAY_PAGE_GROUP_LIBRARY);
- g_object_get (shell->priv->queue_source, "sidebar", &shell->priv->queue_sidebar, NULL);
- gtk_widget_show_all (shell->priv->queue_sidebar);
- gtk_widget_set_no_show_all (shell->priv->queue_sidebar, TRUE);
+ g_setenv ("PULSE_PROP_media.role", "music", TRUE);
+}
- /* places for plugins to put UI */
- shell->priv->top_container = GTK_BOX (gtk_vbox_new (FALSE, 0));
- shell->priv->bottom_container = GTK_BOX (gtk_vbox_new (FALSE, 0));
- shell->priv->sidebar_container = GTK_BOX (gtk_vbox_new (FALSE, 0));
- shell->priv->right_sidebar_container = GTK_BOX (gtk_vbox_new (FALSE, 0));
+static void
+rb_shell_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ RBShell *shell = RB_SHELL (object);
- /* set up sidebars */
- shell->priv->paned = gtk_hpaned_new ();
- shell->priv->right_paned = gtk_hpaned_new ();
- gtk_widget_show_all (shell->priv->right_paned);
- g_signal_connect_object (G_OBJECT (shell->priv->right_paned),
- "size-allocate",
- G_CALLBACK (paned_size_allocate_cb),
- shell, 0);
- gtk_widget_set_no_show_all (shell->priv->right_paned, TRUE);
+ switch (prop_id)
{
- GtkWidget *vbox2 = gtk_vbox_new (FALSE, 0);
+ case PROP_NO_REGISTRATION:
+ shell->priv->no_registration = g_value_get_boolean (value);
+ break;
+ case PROP_NO_UPDATE:
+ shell->priv->no_update = g_value_get_boolean (value);
+ break;
+ case PROP_DRY_RUN:
+ shell->priv->dry_run = g_value_get_boolean (value);
+ if (shell->priv->dry_run)
+ shell->priv->no_registration = TRUE;
+ break;
+ case PROP_RHYTHMDB_FILE:
+ g_free (shell->priv->rhythmdb_file);
+ shell->priv->rhythmdb_file = g_value_dup_string (value);
+ break;
+ case PROP_PLAYLISTS_FILE:
+ g_free (shell->priv->playlists_file);
+ shell->priv->playlists_file = g_value_dup_string (value);
+ break;
+ case PROP_VISIBILITY:
+ rb_shell_set_visibility (shell, FALSE, g_value_get_boolean (value));
+ break;
+ case PROP_AUTOSTARTED:
+ shell->priv->autostarted = g_value_get_boolean (value);
+ break;
+ case PROP_DISABLE_PLUGINS:
+ shell->priv->disable_plugins = g_value_get_boolean (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
- shell->priv->queue_paned = gtk_vpaned_new ();
- gtk_paned_pack1 (GTK_PANED (shell->priv->queue_paned),
- GTK_WIDGET (shell->priv->display_page_tree),
- FALSE, TRUE);
- gtk_paned_pack2 (GTK_PANED (shell->priv->queue_paned),
- shell->priv->queue_sidebar,
- TRUE, TRUE);
- gtk_container_child_set (GTK_CONTAINER (shell->priv->queue_paned),
- GTK_WIDGET (shell->priv->display_page_tree),
- "resize", FALSE,
- NULL);
+static void
+rb_shell_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ RBShell *shell = RB_SHELL (object);
- gtk_box_pack_start (GTK_BOX (vbox2),
- GTK_WIDGET (shell->priv->source_header),
- FALSE, FALSE, 3);
- gtk_box_pack_start (GTK_BOX (vbox2),
- shell->priv->notebook,
- TRUE, TRUE, 0);
- gtk_box_pack_start (GTK_BOX (vbox2),
- GTK_WIDGET (shell->priv->bottom_container),
- FALSE, FALSE, 0);
+ switch (prop_id)
+ {
+ case PROP_NO_REGISTRATION:
+ g_value_set_boolean (value, shell->priv->no_registration);
+ break;
+ case PROP_NO_UPDATE:
+ g_value_set_boolean (value, shell->priv->no_update);
+ break;
+ case PROP_DRY_RUN:
+ g_value_set_boolean (value, shell->priv->dry_run);
+ break;
+ case PROP_RHYTHMDB_FILE:
+ g_value_set_string (value, shell->priv->rhythmdb_file);
+ break;
+ case PROP_PLAYLISTS_FILE:
+ g_value_set_string (value, shell->priv->playlists_file);
+ break;
+ case PROP_DB:
+ g_value_set_object (value, shell->priv->db);
+ break;
+ case PROP_UI_MANAGER:
+ g_value_set_object (value, shell->priv->ui_manager);
+ break;
+ case PROP_CLIPBOARD:
+ g_value_set_object (value, shell->priv->clipboard_shell);
+ break;
+ case PROP_PLAYLIST_MANAGER:
+ g_value_set_object (value, shell->priv->playlist_manager);
+ break;
+ case PROP_SHELL_PLAYER:
+ g_value_set_object (value, shell->priv->player_shell);
+ break;
+ case PROP_REMOVABLE_MEDIA_MANAGER:
+ g_value_set_object (value, shell->priv->removable_media_manager);
+ break;
+ case PROP_SELECTED_PAGE:
+ g_value_set_object (value, shell->priv->selected_page);
+ break;
+ case PROP_WINDOW:
+ g_value_set_object (value, shell->priv->window);
+ break;
+ case PROP_PREFS:
+ /* create the preferences window the first time we need it */
+ if (shell->priv->prefs == NULL) {
+ GtkWidget *content;
- gtk_paned_pack1 (GTK_PANED (shell->priv->right_paned),
- vbox2, TRUE, TRUE);
- gtk_paned_pack2 (GTK_PANED (shell->priv->right_paned),
- GTK_WIDGET (shell->priv->right_sidebar_container),
- FALSE, FALSE);
- gtk_widget_hide (GTK_WIDGET(shell->priv->right_sidebar_container));
+ shell->priv->prefs = rb_shell_preferences_new (shell->priv->sources);
- gtk_box_pack_start (shell->priv->sidebar_container,
- shell->priv->queue_paned,
- TRUE, TRUE, 0);
- gtk_paned_pack1 (GTK_PANED (shell->priv->paned),
- GTK_WIDGET (shell->priv->sidebar_container),
- FALSE, TRUE);
- gtk_paned_pack2 (GTK_PANED (shell->priv->paned),
- shell->priv->right_paned,
- TRUE, TRUE);
- gtk_widget_show (vbox2);
+ gtk_window_set_transient_for (GTK_WINDOW (shell->priv->prefs),
+ GTK_WINDOW (shell->priv->window));
+ content = gtk_dialog_get_content_area (GTK_DIALOG (shell->priv->prefs));
+ gtk_widget_show_all (content);
+ }
+ g_value_set_object (value, shell->priv->prefs);
+ break;
+ case PROP_QUEUE_SOURCE:
+ g_value_set_object (value, shell->priv->queue_source);
+ break;
+ case PROP_LIBRARY_SOURCE:
+ g_value_set_object (value, shell->priv->library_source);
+ break;
+ case PROP_DISPLAY_PAGE_MODEL:
+ g_value_set_object (value, shell->priv->display_page_model);
+ break;
+ case PROP_DISPLAY_PAGE_TREE:
+ g_value_set_object (value, shell->priv->display_page_tree);
+ break;
+ case PROP_VISIBILITY:
+ g_value_set_boolean (value, rb_shell_get_visibility (shell));
+ break;
+ case PROP_SOURCE_HEADER:
+ g_value_set_object (value, shell->priv->source_header);
+ break;
+ case PROP_TRACK_TRANSFER_QUEUE:
+ g_value_set_object (value, shell->priv->track_transfer_queue);
+ break;
+ case PROP_AUTOSTARTED:
+ g_value_set_boolean (value, shell->priv->autostarted);
+ break;
+ case PROP_DISABLE_PLUGINS:
+ g_value_set_boolean (value, shell->priv->disable_plugins);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
}
-
- g_signal_connect_object (G_OBJECT (shell->priv->queue_paned),
- "size-allocate",
- G_CALLBACK (paned_size_allocate_cb),
- shell, 0);
- gtk_widget_show (shell->priv->paned);
-
- shell->priv->main_vbox = gtk_vbox_new (FALSE, 0);
- gtk_container_set_border_width (GTK_CONTAINER (shell->priv->main_vbox), 0);
- gtk_box_pack_start (GTK_BOX (shell->priv->main_vbox), GTK_WIDGET (shell->priv->player_shell), FALSE, TRUE, 6);
- gtk_widget_show (GTK_WIDGET (shell->priv->player_shell));
-
- gtk_box_pack_start (GTK_BOX (shell->priv->main_vbox), GTK_WIDGET (shell->priv->top_container), FALSE, TRUE, 0);
- gtk_box_pack_start (GTK_BOX (shell->priv->main_vbox), shell->priv->paned, TRUE, TRUE, 0);
- gtk_box_pack_start (GTK_BOX (shell->priv->main_vbox), GTK_WIDGET (shell->priv->statusbar), FALSE, TRUE, 0);
- gtk_widget_show_all (shell->priv->main_vbox);
-
- gtk_container_add (GTK_CONTAINER (win), shell->priv->main_vbox);
-
- rb_profile_end ("constructing widgets");
}
-static void
-construct_sources (RBShell *shell)
+static gboolean
+rb_shell_sync_state (RBShell *shell)
{
- RBDisplayPage *page_group;
- char *pathname;
-
- rb_profile_start ("constructing sources");
-
- page_group = RB_DISPLAY_PAGE_GROUP_LIBRARY;
- shell->priv->library_source = RB_LIBRARY_SOURCE (rb_library_source_new (shell));
- shell->priv->podcast_source = RB_PODCAST_SOURCE (rb_podcast_main_source_new (shell, shell->priv->podcast_manager));
- shell->priv->missing_files_source = rb_missing_files_source_new (shell, shell->priv->library_source);
+ if (shell->priv->dry_run) {
+ rb_debug ("in dry-run mode, not syncing state");
+ return FALSE;
+ }
- shell->priv->import_errors_source = rb_import_errors_source_new (shell,
- RHYTHMDB_ENTRY_TYPE_IMPORT_ERROR,
- RHYTHMDB_ENTRY_TYPE_SONG,
- RHYTHMDB_ENTRY_TYPE_IGNORE);
+ if (!shell->priv->load_complete) {
+ rb_debug ("load incomplete, not syncing state");
+ return FALSE;
+ }
- rb_shell_append_display_page (shell, RB_DISPLAY_PAGE (shell->priv->library_source), page_group);
- rb_shell_append_display_page (shell, RB_DISPLAY_PAGE (shell->priv->podcast_source), page_group);
- rb_shell_append_display_page (shell, RB_DISPLAY_PAGE (shell->priv->missing_files_source), page_group);
- rb_shell_append_display_page (shell, RB_DISPLAY_PAGE (shell->priv->import_errors_source), page_group);
+ rb_debug ("saving playlists");
+ rb_playlist_manager_save_playlists (shell->priv->playlist_manager,
+ TRUE);
- rb_podcast_main_source_add_subsources (RB_PODCAST_MAIN_SOURCE (shell->priv->podcast_source));
+ rb_debug ("saving db");
+ rhythmdb_save (shell->priv->db);
+ return FALSE;
+}
- /* Find the playlist name if none supplied */
- if (shell->priv->playlists_file) {
- pathname = g_strdup (shell->priv->playlists_file);
- } else {
- pathname = rb_find_user_data_file ("playlists.xml");
- }
+static gboolean
+idle_save_rhythmdb (RBShell *shell)
+{
+ rhythmdb_save (shell->priv->db);
- /* Initialize playlist manager */
- rb_debug ("shell: creating playlist manager");
- shell->priv->playlist_manager = rb_playlist_manager_new (shell,
- shell->priv->display_page_model,
- shell->priv->display_page_tree,
- pathname);
+ shell->priv->save_db_id = 0;
- g_object_set (shell->priv->clipboard_shell,
- "playlist-manager", shell->priv->playlist_manager,
- NULL);
+ return FALSE;
+}
- g_signal_connect_object (G_OBJECT (shell->priv->playlist_manager), "playlist_added",
- G_CALLBACK (rb_shell_playlist_added_cb), shell, 0);
- g_signal_connect_object (G_OBJECT (shell->priv->playlist_manager), "playlist_created",
- G_CALLBACK (rb_shell_playlist_created_cb), shell, 0);
+static gboolean
+idle_save_playlist_manager (RBShell *shell)
+{
+ GDK_THREADS_ENTER ();
+ rb_playlist_manager_save_playlists (shell->priv->playlist_manager,
+ FALSE);
+ GDK_THREADS_LEAVE ();
- /* Initialize removable media manager */
- rb_debug ("shell: creating removable media manager");
- shell->priv->removable_media_manager = rb_removable_media_manager_new (shell);
+ return TRUE;
+}
- g_signal_connect_object (G_OBJECT (shell->priv->removable_media_manager), "medium_added",
- G_CALLBACK (rb_shell_medium_added_cb), shell, 0);
+static void
+rb_shell_shutdown (RBShell *shell)
+{
+ GdkDisplay *display;
+ if (shell->priv->shutting_down)
+ return;
+ shell->priv->shutting_down = TRUE;
- g_free (pathname);
+ /* Hide the main window and tray icon as soon as possible */
+ display = gtk_widget_get_display (shell->priv->window);
+ gtk_widget_hide (shell->priv->window);
+ gdk_display_sync (display);
- rb_profile_end ("constructing sources");
+ if (shell->priv->plugin_engine != NULL) {
+ g_object_unref (shell->priv->plugin_engine);
+ shell->priv->plugin_engine = NULL;
+ }
+ if (shell->priv->activatable != NULL) {
+ g_object_unref (shell->priv->activatable);
+ shell->priv->activatable = NULL;
+ }
+ if (shell->priv->plugin_settings != NULL) {
+ g_object_unref (shell->priv->plugin_settings);
+ shell->priv->plugin_settings = NULL;
+ }
}
static void
-construct_load_ui (RBShell *shell)
+rb_shell_finalize (GObject *object)
{
- GtkWidget *menubar;
- GtkWidget *toolbar;
- GtkToolItem *tool_item;
- GError *error = NULL;
-
- rb_debug ("shell: loading ui");
- rb_profile_start ("loading ui");
+ RBShell *shell = RB_SHELL (object);
- gtk_ui_manager_insert_action_group (shell->priv->ui_manager,
- shell->priv->actiongroup, 0);
- gtk_ui_manager_add_ui_from_file (shell->priv->ui_manager,
- rb_file ("rhythmbox-ui.xml"), &error);
+ rb_debug ("Finalizing shell");
- gtk_ui_manager_ensure_update (shell->priv->ui_manager);
- gtk_window_add_accel_group (GTK_WINDOW (shell->priv->window),
- gtk_ui_manager_get_accel_group (shell->priv->ui_manager));
- menubar = gtk_ui_manager_get_widget (shell->priv->ui_manager, "/MenuBar");
+ rb_shell_player_stop (shell->priv->player_shell);
- gtk_box_pack_start (GTK_BOX (shell->priv->main_vbox), menubar, FALSE, FALSE, 0);
- gtk_box_reorder_child (GTK_BOX (shell->priv->main_vbox), menubar, 0);
+ if (shell->priv->settings != NULL) {
+ rb_settings_delayed_sync (shell->priv->settings, NULL, NULL, NULL);
+ g_object_unref (shell->priv->settings);
+ }
- toolbar = gtk_ui_manager_get_widget (shell->priv->ui_manager, "/ToolBar");
- gtk_style_context_add_class (gtk_widget_get_style_context (toolbar),
- GTK_STYLE_CLASS_PRIMARY_TOOLBAR);
- g_settings_bind (shell->priv->settings, "toolbar-visible",
- toolbar, "visible",
- G_SETTINGS_BIND_DEFAULT);
- gtk_box_pack_start (GTK_BOX (shell->priv->main_vbox), toolbar, FALSE, FALSE, 0);
- gtk_box_reorder_child (GTK_BOX (shell->priv->main_vbox), toolbar, 1);
+ g_free (shell->priv->cached_title);
- shell->priv->volume_button = gtk_volume_button_new ();
- g_signal_connect (shell->priv->volume_button, "value-changed",
- G_CALLBACK (rb_shell_volume_widget_changed_cb),
- shell);
- g_signal_connect (shell->priv->player_shell, "notify::volume",
- G_CALLBACK (rb_shell_player_volume_changed_cb),
- shell);
- rb_shell_player_volume_changed_cb (shell->priv->player_shell, NULL, shell);
+ if (shell->priv->save_playlist_id > 0) {
+ g_source_remove (shell->priv->save_playlist_id);
+ shell->priv->save_playlist_id = 0;
+ }
- tool_item = gtk_tool_item_new ();
- gtk_tool_item_set_expand (tool_item, TRUE);
- gtk_widget_show (GTK_WIDGET (tool_item));
- gtk_toolbar_insert (GTK_TOOLBAR (toolbar), tool_item, -1);
+ if (shell->priv->save_db_id > 0) {
+ g_source_remove (shell->priv->save_db_id);
+ shell->priv->save_db_id = 0;
+ }
- tool_item = gtk_tool_item_new ();
- gtk_container_add (GTK_CONTAINER (tool_item), shell->priv->volume_button);
- gtk_widget_show_all (GTK_WIDGET (tool_item));
- gtk_toolbar_insert (GTK_TOOLBAR (toolbar), tool_item, -1);
+ if (shell->priv->queue_sidebar != NULL) {
+ g_object_unref (shell->priv->queue_sidebar);
+ }
- gtk_widget_set_tooltip_text (shell->priv->volume_button,
- _("Change the music volume"));
+ if (shell->priv->playlist_manager != NULL) {
+ rb_debug ("shutting down playlist manager");
+ rb_playlist_manager_shutdown (shell->priv->playlist_manager);
- if (error != NULL) {
- g_warning ("Couldn't merge %s: %s",
- rb_file ("rhythmbox-ui.xml"), error->message);
- g_clear_error (&error);
+ rb_debug ("unreffing playlist manager");
+ g_object_unref (shell->priv->playlist_manager);
}
- rb_profile_end ("loading ui");
-}
-
-static void
-extension_added_cb (PeasExtensionSet *set, PeasPluginInfo *info, PeasExtension *extension, RBShell *shell)
-{
- rb_debug ("activating extension %s", peas_plugin_info_get_name (info));
- peas_extension_call (extension, "activate");
-}
+ if (shell->priv->removable_media_manager != NULL) {
+ rb_debug ("unreffing removable media manager");
+ g_object_unref (shell->priv->removable_media_manager);
+ g_object_unref (shell->priv->track_transfer_queue);
+ }
-static void
-extension_removed_cb (PeasExtensionSet *set, PeasPluginInfo *info, PeasExtension *extension, RBShell *shell)
-{
- rb_debug ("deactivating extension %s", peas_plugin_info_get_name (info));
- peas_extension_call (extension, "deactivate");
-}
+ if (shell->priv->podcast_manager != NULL) {
+ rb_debug ("unreffing podcast manager");
+ g_object_unref (shell->priv->podcast_manager);
+ }
-static void
-construct_plugins (RBShell *shell)
-{
- char *typelib_dir;
- char *plugindir;
- char *plugindatadir;
- const GList *plugins;
- const GList *l;
- GError *error = NULL;
+ if (shell->priv->clipboard_shell != NULL) {
+ rb_debug ("unreffing clipboard shell");
+ g_object_unref (shell->priv->clipboard_shell);
+ }
- if (shell->priv->disable_plugins) {
- return;
+ if (shell->priv->prefs != NULL) {
+ rb_debug ("destroying prefs");
+ gtk_widget_destroy (shell->priv->prefs);
}
- rb_profile_start ("loading plugins");
- shell->priv->plugin_settings = g_settings_new ("org.gnome.rhythmbox.plugins");
+ g_free (shell->priv->rhythmdb_file);
- shell->priv->plugin_engine = peas_engine_new ();
- /* need an #ifdef for this? */
- peas_engine_enable_loader (shell->priv->plugin_engine, "python");
+ g_free (shell->priv->playlists_file);
- typelib_dir = g_build_filename (LIBDIR,
- "girepository-1.0",
- NULL);
- if (g_irepository_require_private (g_irepository_get_default (),
- typelib_dir, "MPID", "3.0", 0, &error) == FALSE) {
- g_clear_error (&error);
- if (g_irepository_require (g_irepository_get_default (), "MPID", "3.0", 0, &error) == FALSE) {
- g_warning ("Could not load MPID typelib: %s", error->message);
- g_clear_error (&error);
- }
- }
+ rb_debug ("destroying window");
+ gtk_widget_destroy (shell->priv->window);
- if (g_irepository_require_private (g_irepository_get_default (),
- typelib_dir, "RB", "3.0", 0, &error) == FALSE) {
- g_clear_error (&error);
- if (g_irepository_require (g_irepository_get_default (), "RB", "3.0", 0, &error) == FALSE) {
- g_warning ("Could not load RB typelib: %s", error->message);
- g_clear_error (&error);
- }
- }
- g_free (typelib_dir);
+ g_list_free (shell->priv->sources);
+ shell->priv->sources = NULL;
- if (g_irepository_require (g_irepository_get_default (), "Peas", "1.0", 0, &error) == FALSE) {
- g_warning ("Could not load Peas typelib: %s", error->message);
- g_clear_error (&error);
+ if (shell->priv->sources_hash != NULL) {
+ g_hash_table_destroy (shell->priv->sources_hash);
}
- if (g_irepository_require (g_irepository_get_default (), "PeasGtk", "1.0", 0, &error) == FALSE) {
- g_warning ("Could not load PeasGtk typelib: %s", error->message);
- g_clear_error (&error);
+ if (shell->priv->db != NULL) {
+ rb_debug ("shutting down DB");
+ rhythmdb_shutdown (shell->priv->db);
+
+ rb_debug ("unreffing DB");
+ g_object_unref (shell->priv->db);
}
- plugindir = g_build_filename (rb_user_data_dir (), "plugins", NULL);
- rb_debug ("plugin search path: %s", plugindir);
- peas_engine_add_search_path (shell->priv->plugin_engine,
- plugindir,
- plugindir);
- g_free (plugindir);
+ rb_file_helpers_shutdown ();
+ rb_stock_icons_shutdown ();
+ rb_refstring_system_shutdown ();
- plugindir = g_build_filename (LIBDIR, "rhythmbox", "plugins", NULL);
- plugindatadir = g_build_filename (DATADIR, "rhythmbox", "plugins", NULL);
- rb_debug ("plugin search path: %s / %s", plugindir, plugindatadir);
- peas_engine_add_search_path (shell->priv->plugin_engine,
- plugindir,
- plugindatadir);
- g_free (plugindir);
- g_free (plugindatadir);
+ G_OBJECT_CLASS (rb_shell_parent_class)->finalize (object);
-#ifdef USE_UNINSTALLED_DIRS
- plugindir = g_build_filename (SHARE_UNINSTALLED_BUILDDIR, "..", UNINSTALLED_PLUGINS_LOCATION, NULL);
- rb_debug ("plugin search path: %s", plugindir);
- peas_engine_add_search_path (shell->priv->plugin_engine,
- plugindir,
- plugindir);
- g_free (plugindir);
-#endif
+ rb_debug ("shell shutdown complete");
+}
- shell->priv->activatable = peas_extension_set_new (shell->priv->plugin_engine,
- PEAS_TYPE_ACTIVATABLE,
- "object", shell,
- NULL);
- g_signal_connect (shell->priv->activatable, "extension-added", G_CALLBACK (extension_added_cb), shell);
- g_signal_connect (shell->priv->activatable, "extension-removed", G_CALLBACK (extension_removed_cb), shell);
+/**
+ * rb_shell_new:
+ * @autostarted: %TRUE if autostarted by the session manager
+ * @argc: a pointer to the number of command line arguments
+ * @argv: a pointer to the array of command line arguments
+ *
+ * Creates the Rhythmbox shell. This is effectively a singleton, so it doesn't
+ * make sense to call this from anywhere other than main.c.
+ *
+ * Return value: the #RBShell instance
+ */
+RBShell *
+rb_shell_new (gboolean autostarted, int *argc, char ***argv)
+{
+ GOptionContext *context;
+ gboolean debug = FALSE;
+ char *debug_match = NULL;
+ gboolean no_update = FALSE;
+ gboolean no_registration = FALSE;
+ gboolean dry_run = FALSE;
+ gboolean disable_plugins = FALSE;
+ char *rhythmdb_file = NULL;
+ char *playlists_file = NULL;
+ GError *error = NULL;
- g_settings_bind (shell->priv->plugin_settings,
- "active-plugins",
- shell->priv->plugin_engine,
- "loaded-plugins",
- G_SETTINGS_BIND_DEFAULT);
+ const GOptionEntry options [] = {
+ { "debug", 'd', 0, G_OPTION_ARG_NONE, &debug, N_("Enable debug output"), NULL },
+ { "debug-match", 'D', 0, G_OPTION_ARG_STRING, &debug_match, N_("Enable debug output matching a specified string"), NULL },
+ { "no-update", 0, 0, G_OPTION_ARG_NONE, &no_update, N_("Do not update the library with file changes"), NULL },
+ { "no-registration", 'n', 0, G_OPTION_ARG_NONE, &no_registration, N_("Do not register the shell"), NULL },
+ { "dry-run", 0, 0, G_OPTION_ARG_NONE, &dry_run, N_("Don't save any data permanently (implies --no-registration)"), NULL },
+ { "disable-plugins", 0, 0, G_OPTION_ARG_NONE, &disable_plugins, N_("Disable loading of plugins"), NULL },
+ { "rhythmdb-file", 0, 0, G_OPTION_ARG_STRING, &rhythmdb_file, N_("Path for database file to use"), NULL },
+ { "playlists-file", 0, 0, G_OPTION_ARG_STRING, &playlists_file, N_("Path for playlists file to use"), NULL },
+ { NULL }
+ };
- /* load builtin plugins */
- plugins = peas_engine_get_plugin_list (shell->priv->plugin_engine);
- for (l = plugins; l != NULL; l = l->next) {
- PeasPluginInfo *info = PEAS_PLUGIN_INFO (l->data);
- if (peas_plugin_info_is_builtin (info) &&
- g_strcmp0 (peas_plugin_info_get_module_name (info), "rb") != 0) {
- peas_engine_load_plugin (shell->priv->plugin_engine, info);
- }
+ context = g_option_context_new (NULL);
+ g_option_context_add_main_entries (context, options, GETTEXT_PACKAGE);
+ g_option_context_add_group (context, gst_init_get_option_group ());
+ g_option_context_add_group (context, egg_sm_client_get_option_group ());
+ g_option_context_add_group (context, gtk_get_option_group (TRUE));
+
+ if (g_option_context_parse (context, argc, argv, &error) == FALSE) {
+ g_print (_("%s\nRun '%s --help' to see a full list of available command line options.\n"),
+ error->message, (*argv)[0]);
+ g_error_free (error);
+ g_option_context_free (context);
+ exit (1);
}
+ g_option_context_free (context);
- rb_profile_end ("loading plugins");
+ if (!debug && debug_match)
+ rb_debug_init_match (debug_match);
+ else
+ rb_debug_init (debug);
+
+ return g_object_new (RB_TYPE_SHELL,
+ "application-id", "org.gnome.Rhythmbox3",
+ "flags", G_APPLICATION_HANDLES_OPEN,
+ "autostarted", autostarted,
+ "no-registration", no_registration,
+ "no-update", no_update,
+ "dry-run", dry_run,
+ "rhythmdb-file", rhythmdb_file,
+ "playlists-file", playlists_file,
+ "disable-plugins", disable_plugins,
+ NULL);
}
-static gboolean
-_scan_idle (RBShell *shell)
+static void
+load_uri_action_cb (GSimpleAction *action, GVariant *parameters, RBShell *shell)
{
- GDK_THREADS_ENTER ();
- rb_removable_media_manager_scan (shell->priv->removable_media_manager);
- GDK_THREADS_LEAVE ();
- g_signal_emit (shell, rb_shell_signals[REMOVABLE_MEDIA_SCAN_FINISHED], 0);
- return FALSE;
+ const char *uri;
+ gboolean play;
+
+ g_variant_get (parameters, "(&sb)", &uri, &play);
+
+ rb_shell_load_uri (shell, uri, play, NULL);
+}
+
+static void
+activate_source_action_cb (GSimpleAction *action, GVariant *parameters, RBShell *shell)
+{
+ const char *source;
+ guint play;
+
+ g_variant_get (parameters, "(&su)", &source, &play);
+ rb_shell_activate_source_by_uri (shell, source, play, NULL);
+}
+
+static void
+quit_action_cb (GSimpleAction *action, GVariant *parameters, RBShell *shell)
+{
+ rb_shell_quit (shell, NULL);
}
static void
rb_shell_constructed (GObject *object)
{
RBShell *shell;
- GtkAction *action;
+ GSimpleActionGroup *actions;
+ GSimpleAction *action;
+
+ gtk_init (NULL, NULL);
RB_CHAIN_GOBJECT_METHOD (rb_shell_parent_class, constructed, object);
shell = RB_SHELL (object);
- rb_debug ("Constructing shell");
- rb_profile_start ("constructing shell");
+ /* create application actions */
+ actions = g_simple_action_group_new ();
+ action = g_simple_action_new_stateful ("LoadURI", G_VARIANT_TYPE ("(sb)"), g_variant_new ("(bb)", FALSE, FALSE));
+ g_signal_connect_object (action, "activate", G_CALLBACK (load_uri_action_cb), shell, 0);
+ g_simple_action_group_insert (actions, G_ACTION (action));
+ g_object_unref (action);
+
+ action = g_simple_action_new ("ActivateSource", G_VARIANT_TYPE ("(su)"));
+ g_signal_connect_object (action, "activate", G_CALLBACK (activate_source_action_cb), shell, 0);
+ g_simple_action_group_insert (actions, G_ACTION (action));
+ g_object_unref (action);
+
+ action = g_simple_action_new ("Quit", NULL);
+ g_signal_connect_object (action, "activate", G_CALLBACK (quit_action_cb), shell, 0);
+ g_simple_action_group_insert (actions, G_ACTION (action));
+ g_object_unref (action);
+
+ g_application_set_action_group (G_APPLICATION (shell), G_ACTION_GROUP (actions));
+
+ /* construct enough of the rest of it to display the window if required */
shell->priv->settings = g_settings_new ("org.gnome.rhythmbox");
@@ -1670,81 +1967,7 @@ rb_shell_constructed (GObject *object)
construct_db (shell);
- /* initialize shell services */
construct_widgets (shell);
-
- g_signal_connect_object (shell->priv->settings, "changed", G_CALLBACK (settings_changed_cb), shell, 0);
-
- action = gtk_action_group_get_action (shell->priv->actiongroup, "ViewSidePane");
- g_settings_bind (shell->priv->settings, "display-page-tree-visible",
- action, "active",
- G_SETTINGS_BIND_DEFAULT);
- g_settings_bind (shell->priv->settings, "display-page-tree-visible",
- shell->priv->sidebar_container, "visible",
- G_SETTINGS_BIND_DEFAULT);
-
- action = gtk_action_group_get_action (shell->priv->actiongroup, "ViewToolbar");
- g_settings_bind (shell->priv->settings, "toolbar-visible",
- action, "active",
- G_SETTINGS_BIND_DEFAULT);
-
- rb_debug ("shell: syncing with settings");
- rb_shell_sync_pane_visibility (shell);
-
- g_signal_connect_object (G_OBJECT (shell->priv->db), "save-error",
- G_CALLBACK (rb_shell_db_save_error_cb), shell, 0);
-
- construct_sources (shell);
-
- construct_load_ui (shell);
-
- construct_plugins (shell);
-
- rb_shell_sync_window_state (shell, FALSE);
- rb_shell_sync_smalldisplay (shell);
- rb_shell_sync_party_mode (shell);
- rb_shell_sync_toolbar_state (shell);
-
- rb_shell_select_page (shell, RB_DISPLAY_PAGE (shell->priv->library_source));
-
- /* by now we've added the built in sources and any sources from plugins,
- * so we can consider the fixed page groups loaded
- */
- rb_display_page_group_loaded (RB_DISPLAY_PAGE_GROUP (RB_DISPLAY_PAGE_GROUP_LIBRARY));
- rb_display_page_group_loaded (RB_DISPLAY_PAGE_GROUP (RB_DISPLAY_PAGE_GROUP_STORES));
-
- rb_missing_plugins_init (GTK_WINDOW (shell->priv->window));
-
- g_idle_add ((GSourceFunc)_scan_idle, shell);
-
- /* GO GO GO! */
- rb_debug ("loading database");
- rhythmdb_load (shell->priv->db);
-
- rb_debug ("shell: syncing window state");
- rb_shell_sync_paned (shell);
-
- /* set initial visibility */
- rb_shell_set_visibility (shell, TRUE, TRUE);
-
- gdk_notify_startup_complete ();
-
- /* focus play if small, the entry view if not */
- if (g_settings_get_boolean (shell->priv->settings, "small-display")) {
- GtkWidget *play_button;
-
- play_button = gtk_ui_manager_get_widget (shell->priv->ui_manager, "/ToolBar/Play");
- gtk_widget_grab_focus (play_button);
- } else {
- RBEntryView *view;
-
- view = rb_source_get_entry_view (RB_SOURCE (shell->priv->library_source));
- if (view != NULL) {
- gtk_widget_grab_focus (GTK_WIDGET (view));
- }
- }
-
- rb_profile_end ("constructing shell");
}
static gboolean
@@ -2727,7 +2950,8 @@ rb_shell_quit (RBShell *shell,
rb_shell_shutdown (shell);
rb_shell_sync_state (shell);
- g_object_unref (G_OBJECT (shell));
+
+ g_application_release (G_APPLICATION (shell));
g_timeout_add_seconds (10, quit_timeout, NULL);
return TRUE;
@@ -2736,6 +2960,7 @@ rb_shell_quit (RBShell *shell,
static gboolean
idle_handle_load_complete (RBShell *shell)
{
+ gboolean loaded, scanned;
GDK_THREADS_ENTER ();
rb_debug ("load complete");
@@ -2745,7 +2970,11 @@ idle_handle_load_complete (RBShell *shell)
shell->priv->load_complete = TRUE;
shell->priv->save_playlist_id = g_timeout_add_seconds (10, (GSourceFunc) idle_save_playlist_manager, shell);
- g_signal_emit (shell, rb_shell_signals[DATABASE_LOAD_COMPLETE], 0);
+ if (shell->priv->no_registration == FALSE) {
+ g_variant_get (g_action_group_get_action_state (G_ACTION_GROUP (shell), "LoadURI"), "(bb)", &loaded, &scanned);
+ g_action_group_change_action_state (G_ACTION_GROUP (shell), "LoadURI", g_variant_new ("(bb)", TRUE, scanned));
+ emit_action_state_update (shell, "LoadURI");
+ }
rhythmdb_start_action_thread (shell->priv->db);
@@ -3471,153 +3700,6 @@ rb_shell_get_party_mode (RBShell *shell)
}
/**
- * rb_shell_get_player:
- * @shell: the #RBShell
- *
- * Returns the #RBShellPlayer object
- *
- * Return value: (transfer none): the #RBShellPlayer object
- */
-GObject *
-rb_shell_get_player (RBShell *shell)
-{
- return G_OBJECT (shell->priv->player_shell);
-}
-
-/**
- * rb_shell_get_player_path:
- * @shell: the #RBShell
- *
- * Returns the DBus object path for the #RBShellPlayer
- *
- * Return value: the DBus object path for the #RBShellPlayer
- */
-const char *
-rb_shell_get_player_path (RBShell *shell)
-{
- return "/org/gnome/Rhythmbox/Player";
-}
-
-/**
- * rb_shell_get_playlist_manager:
- * @shell: the #RBShell
- *
- * Returns the #RBPlaylistManager object
- *
- * Return value: (transfer none): the #RBPlaylistManager object
- */
-GObject *
-rb_shell_get_playlist_manager (RBShell *shell)
-{
- return G_OBJECT (shell->priv->playlist_manager);
-}
-
-/**
- * rb_shell_get_playlist_manager_path:
- * @shell: the #RBShell
- *
- * Returns the DBus path for the #RBPlaylistManager object
- *
- * Return value: the DBus object path for the #RBPlaylistManager
- */
-const char *
-rb_shell_get_playlist_manager_path (RBShell *shell)
-{
- return "/org/gnome/Rhythmbox/PlaylistManager";
-}
-
-/**
- * rb_shell_get_ui_manager:
- * @shell: the #RBShell
- *
- * Returns the main #GtkUIManager object
- *
- * Return value: (transfer none): the main #GtkUIManager object
- */
-GObject *
-rb_shell_get_ui_manager (RBShell *shell)
-{
- return G_OBJECT (shell->priv->ui_manager);
-}
-
-/**
- * rb_shell_add_to_queue:
- * @shell: the #RBShell
- * @uri: the URI to add to the play queue
- * @error: not used
- *
- * Adds the specified URI to the play queue. This only works if URI is already
- * in the database.
- *
- * Return value: not used
- */
-gboolean
-rb_shell_add_to_queue (RBShell *shell,
- const gchar *uri,
- GError **error)
-{
- RhythmDBEntry *entry;
-
- entry = rhythmdb_entry_lookup_by_location (shell->priv->db, uri);
- if (entry == NULL) {
- RBSource *source;
- source = rb_shell_guess_source_for_uri (shell, uri);
- if (source != NULL) {
- rb_source_add_uri (source, uri, NULL, NULL, NULL, NULL, NULL);
- } else {
- g_set_error (error,
- RB_SHELL_ERROR,
- RB_SHELL_ERROR_NO_SOURCE_FOR_URI,
- _("No registered source can handle URI %s"),
- uri);
- return FALSE;
- }
- }
- rb_static_playlist_source_add_location (RB_STATIC_PLAYLIST_SOURCE (shell->priv->queue_source),
- uri, -1);
- return TRUE;
-}
-
-/**
- * rb_shell_remove_from_queue:
- * @shell: the #RBShell
- * @uri: the URI to remove from the play queue
- * @error: not used
- *
- * Removes the specified URI from the play queue. If the URI is not
- * in the play queue, nothing happens.
- *
- * Return value: not used.
- */
-gboolean
-rb_shell_remove_from_queue (RBShell *shell,
- const gchar *uri,
- GError **error)
-{
- if (rb_playlist_source_location_in_map (RB_PLAYLIST_SOURCE (shell->priv->queue_source), uri))
- rb_static_playlist_source_remove_location (RB_STATIC_PLAYLIST_SOURCE (shell->priv->queue_source),
- uri);
- return TRUE;
-}
-
-/**
- * rb_shell_clear_queue:
- * @shell: the #RBShell
- * @error: not used
- *
- * Removes all entries from the play queue.
- *
- * Return value: not used
- */
-gboolean
-rb_shell_clear_queue (RBShell *shell,
- GError **error)
-{
- rb_play_queue_source_clear_queue (RB_PLAY_QUEUE_SOURCE (shell->priv->queue_source));
- return TRUE;
-}
-
-/**
* rb_shell_present:
* @shell: the #RBShell
* @timestamp: GTK timestamp to use (for focus-stealing prevention)
diff --git a/shell/rb-shell.h b/shell/rb-shell.h
index a9ef0b0..e5c92f9 100644
--- a/shell/rb-shell.h
+++ b/shell/rb-shell.h
@@ -84,14 +84,14 @@ typedef struct _RBShellPrivate RBShellPrivate;
struct _RBShell
{
- GObject parent;
+ GtkApplication parent;
RBShellPrivate *priv;
};
struct _RBShellClass
{
- GObjectClass parent_class;
+ GtkApplicationClass parent_class;
/* signals */
gboolean (*visibility_changing) (RBShell *shell, gboolean initial, gboolean visible);
@@ -103,13 +103,7 @@ struct _RBShellClass
GType rb_shell_get_type (void);
-RBShell * rb_shell_new (gboolean no_registration,
- gboolean no_update,
- gboolean dry_run,
- gboolean autostarted,
- gboolean disable_plugins,
- char *rhythmdb,
- char *playlists);
+RBShell * rb_shell_new (gboolean autostarted, int *argc, char ***argv);
gboolean rb_shell_present (RBShell *shell, guint32 timestamp, GError **error);
@@ -123,12 +117,6 @@ gboolean rb_shell_add_uri (RBShell *shell,
gboolean rb_shell_load_uri (RBShell *shell, const char *uri, gboolean play, GError **error);
-GObject * rb_shell_get_player (RBShell *shell);
-const char * rb_shell_get_player_path(RBShell *shell);
-GObject * rb_shell_get_playlist_manager (RBShell *shell);
-const char * rb_shell_get_playlist_manager_path (RBShell *shell);
-GObject * rb_shell_get_ui_manager (RBShell *shell);
-
void rb_shell_toggle_visibility (RBShell *shell);
gboolean rb_shell_get_song_properties (RBShell *shell,
@@ -142,17 +130,6 @@ gboolean rb_shell_set_song_property (RBShell *shell,
const GValue *value,
GError **error);
-gboolean rb_shell_add_to_queue (RBShell *shell,
- const gchar *uri,
- GError **error);
-
-gboolean rb_shell_remove_from_queue (RBShell *shell,
- const gchar *uri,
- GError **error);
-
-gboolean rb_shell_clear_queue (RBShell *shell,
- GError **error);
-
gboolean rb_shell_quit (RBShell *shell,
GError **error);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]