1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
3 * arch-tag: Implementation of main Rhythmbox shell
5 * Copyright (C) 2002, 2003 Jorn Baayen
6 * Copyright (C) 2003, 2004 Colin Walters <walters@gnome.org>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2, or (at your option)
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
31 #include <glib/gi18n.h>
36 #include <X11/Xatom.h>
38 #include <libgnome/libgnome.h>
39 #include <libgnome/gnome-init.h>
40 #include <libgnome/gnome-program.h>
41 #include <libgnomeui/gnome-client.h>
43 #include <libgnomevfs/gnome-vfs.h>
44 #include <libgnomevfs/gnome-vfs-mime-utils.h>
48 #include "rb-dialog.h"
49 #ifdef WITH_RHYTHMDB_TREE
50 #include "rhythmdb-tree.h"
51 #elif defined(WITH_RHYTHMDB_GDA)
52 #include "rhythmdb-gda.h"
54 #error "no database specified. configure broken?"
56 #include "rb-stock-icons.h"
57 #include "rb-sourcelist.h"
58 #include "rb-file-helpers.h"
59 #include "rb-source.h"
60 #include "rb-playlist-manager.h"
61 #include "rb-removable-media-manager.h"
62 #include "rb-preferences.h"
64 #include "rb-shell-clipboard.h"
65 #include "rb-shell-player.h"
66 #include "rb-source-header.h"
67 #include "rb-tray-icon.h"
68 #include "rb-statusbar.h"
69 #include "rb-shell-preferences.h"
70 #include "rb-library-source.h"
71 #include "rb-podcast-source.h"
72 #include "totem-pl-parser.h"
73 #include "rb-shell-preferences.h"
74 #include "rb-playlist-source.h"
75 #include "rb-static-playlist-source.h"
76 #include "rb-play-queue-source.h"
77 #include "eel-gconf-extensions.h"
78 #include "bacon-volume.h"
79 #include "rb-missing-files-source.h"
80 #include "rb-import-errors-source.h"
81 #include "rb-plugins-engine.h"
82 #include "rb-plugin-manager.h"
83 #include "rb-proxy-config.h"
85 #include "rb-sourcelist-model.h"
86 #include "rb-song-info.h"
87 #include "rb-marshal.h"
89 static void rb_shell_class_init (RBShellClass
*klass
);
90 static void rb_shell_init (RBShell
*shell
);
91 static GObject
*rb_shell_constructor (GType type
,
92 guint n_construct_properties
,
93 GObjectConstructParam
*construct_properties
);
94 static void rb_shell_finalize (GObject
*object
);
95 static void rb_shell_set_property (GObject
*object
,
99 static void rb_shell_get_property (GObject
*object
,
103 static gboolean
rb_shell_get_visibility (RBShell
*shell
);
104 static gboolean
rb_shell_window_state_cb (GtkWidget
*widget
,
105 GdkEventWindowState
*event
,
107 static gboolean
rb_shell_window_configure_cb (GtkWidget
*win
,
108 GdkEventConfigure
*event
,
110 static gboolean
rb_shell_window_delete_cb (GtkWidget
*win
,
113 static void rb_shell_sync_window_state (RBShell
*shell
, gboolean dont_maximise
);
114 static void rb_shell_sync_paned (RBShell
*shell
);
115 static void rb_shell_sync_party_mode (RBShell
*shell
);
116 static void rb_shell_select_source (RBShell
*shell
, RBSource
*source
);
117 static void source_selected_cb (RBSourceList
*sourcelist
,
120 static void rb_shell_playing_source_changed_cb (RBShellPlayer
*player
,
123 static void rb_shell_playing_entry_changed_cb (RBShellPlayer
*player
,
124 RhythmDBEntry
*entry
,
126 static void rb_shell_playing_from_queue_cb (RBShellPlayer
*player
,
129 static void source_activated_cb (RBSourceList
*sourcelist
,
132 static void rb_shell_db_save_error_cb (RhythmDB
*db
,
133 const char *uri
, const GError
*error
,
135 static void rb_shell_db_entry_added_cb (RhythmDB
*db
,
136 RhythmDBEntry
*entry
,
138 static void rb_shell_druid_response_cb (GtkDialog
*druid
,
142 static void rb_shell_playlist_added_cb (RBPlaylistManager
*mgr
, RBSource
*source
, RBShell
*shell
);
143 static void rb_shell_playlist_created_cb (RBPlaylistManager
*mgr
, RBSource
*source
, RBShell
*shell
);
144 static void rb_shell_medium_added_cb (RBRemovableMediaManager
*mgr
, RBSource
*source
, RBShell
*shell
);
145 static void rb_shell_transfer_progress_cb (RBRemovableMediaManager
*mgr
,
150 static void rb_shell_source_deleted_cb (RBSource
*source
, RBShell
*shell
);
151 static void rb_shell_set_window_title (RBShell
*shell
, const char *window_title
);
152 static void rb_shell_set_elapsed (RBShell
*shell
, guint elapsed
);
153 static void rb_shell_player_window_title_changed_cb (RBShellPlayer
*player
,
154 const char *window_title
,
156 static void rb_shell_player_elapsed_changed_cb (RBShellPlayer
*player
,
159 static void rb_shell_cmd_about (GtkAction
*action
,
161 static void rb_shell_cmd_contents (GtkAction
*action
,
163 static void rb_shell_cmd_toggle_visibility (GtkAction
*action
,
165 static void rb_shell_cmd_quit (GtkAction
*action
,
167 static void rb_shell_cmd_preferences (GtkAction
*action
,
169 static void rb_shell_cmd_plugins (GtkAction
*action
,
171 static void rb_shell_cmd_add_folder_to_library (GtkAction
*action
,
173 static void rb_shell_cmd_add_file_to_library (GtkAction
*action
,
176 static void rb_shell_cmd_current_song (GtkAction
*action
,
178 static void rb_shell_jump_to_current (RBShell
*shell
);
179 static void rb_shell_jump_to_entry_with_source (RBShell
*shell
, RBSource
*source
,
180 RhythmDBEntry
*entry
);
181 static void rb_shell_play_entry (RBShell
*shell
, RhythmDBEntry
*entry
);
182 static void rb_shell_cmd_view_all (GtkAction
*action
,
184 static void rb_shell_view_sidepane_changed_cb (GtkAction
*action
,
186 static void rb_shell_view_toolbar_changed_cb (GtkAction
*action
,
188 static void rb_shell_view_party_mode_changed_cb (GtkAction
*action
,
190 static void rb_shell_view_smalldisplay_changed_cb (GtkAction
*action
,
192 static void rb_shell_view_statusbar_changed_cb (GtkAction
*action
,
194 static void rb_shell_view_queue_as_sidebar_changed_cb (GtkAction
*action
,
196 static void rb_shell_load_complete_cb (RhythmDB
*db
, RBShell
*shell
);
197 static void rb_shell_sync_sidepane_visibility (RBShell
*shell
);
198 static void rb_shell_sync_toolbar_state (RBShell
*shell
);
199 static void rb_shell_sync_smalldisplay (RBShell
*shell
);
200 static void rb_shell_sync_pane_visibility (RBShell
*shell
);
201 static void rb_shell_sync_statusbar_visibility (RBShell
*shell
);
202 static void rb_shell_set_visibility (RBShell
*shell
,
205 static void sidepane_visibility_changed_cb (GConfClient
*client
,
209 static void toolbar_state_changed_cb (GConfClient
*client
,
213 static void smalldisplay_changed_cb (GConfClient
*client
,
217 static void sourcelist_drag_received_cb (RBSourceList
*sourcelist
,
219 GtkSelectionData
*data
,
221 static gboolean
rb_shell_show_popup_cb (RBSourceList
*sourcelist
,
224 static gboolean
tray_destroy_cb (GtkObject
*object
, RBShell
*shell
);
226 static gboolean
save_yourself_cb (GnomeClient
*client
,
228 GnomeSaveStyle save_style
,
230 GnomeInteractStyle interact_style
,
233 static void paned_size_allocate_cb (GtkWidget
*widget
,
234 GtkAllocation
*allocation
,
236 static void sidebar_paned_size_allocate_cb (GtkWidget
*widget
,
237 GtkAllocation
*allocation
,
239 static void rb_shell_volume_widget_changed_cb (BaconVolumeButton
*vol
,
241 static void rb_shell_player_volume_changed_cb (RBShellPlayer
*player
,
245 static void session_die_cb (GnomeClient
*client
, RBShell
*shell
);
246 static void rb_shell_session_init (RBShell
*shell
);
253 PROP_NO_REGISTRATION
,
258 PROP_SELECTED_SOURCE
,
262 PROP_PLAYLIST_MANAGER
,
263 PROP_REMOVABLE_MEDIA_MANAGER
,
270 PROP_SOURCELIST_MODEL
,
275 #define CONF_STATE_WINDOW_WIDTH CONF_PREFIX "/state/window_width"
276 #define CONF_STATE_WINDOW_HEIGHT CONF_PREFIX "/state/window_height"
277 #define CONF_STATE_SMALL_WIDTH CONF_PREFIX "/state/small_width"
278 #define CONF_STATE_WINDOW_MAXIMIZED CONF_PREFIX "/state/window_maximized"
279 #define CONF_STATE_PANED_POSITION CONF_PREFIX "/state/paned_position"
280 #define CONF_STATE_ADD_DIR CONF_PREFIX "/state/add_dir"
281 #define CONF_STATE_WINDOW_X_POSITION CONF_PREFIX "/state/window_x_position"
282 #define CONF_STATE_WINDOW_Y_POSITION CONF_PREFIX "/state/window_y_position"
283 #define CONF_STATE_SOURCELIST_HEIGHT CONF_PREFIX "/state/sourcelist_height"
292 static guint rb_shell_signals
[LAST_SIGNAL
] = { 0 };
294 G_DEFINE_TYPE (RBShell
, rb_shell
, G_TYPE_OBJECT
)
296 struct RBShellPrivate
300 guint idle_hide_mainwindow_id
;
302 GtkUIManager
*ui_manager
;
303 GtkActionGroup
*actiongroup
;
304 guint source_ui_merge_id
;
306 GtkWidget
*main_vbox
;
308 GtkWidget
*sourcelist
;
310 GtkWidget
*queue_paned
;
311 GtkWidget
*queue_sidebar
;
313 GtkBox
*sidebar_container
;
314 GtkBox
*top_container
;
315 GtkBox
*bottom_container
;
318 GHashTable
*sources_hash
;
320 guint async_state_save_id
;
321 guint save_playlist_id
;
324 gboolean shutting_down
;
325 gboolean load_complete
;
329 gboolean no_registration
;
333 char *playlists_file
;
338 RBShellPlayer
*player_shell
;
339 RBShellClipboard
*clipboard_shell
;
340 RBSourceHeader
*source_header
;
341 RBStatusbar
*statusbar
;
342 RBPlaylistManager
*playlist_manager
;
343 RBRemovableMediaManager
*removable_media_manager
;
345 GList
*supported_media_extensions
;
347 RBLibrarySource
*library_source
;
348 RBPodcastSource
*podcast_source
;
349 RBPlaylistSource
*queue_source
;
350 RBSource
*missing_files_source
;
351 RBSource
*import_errors_source
;
353 RBProxyConfig
*proxy_config
;
355 RBSource
*selected_source
;
360 RBTrayIcon
*tray_icon
;
361 GtkTooltips
*tooltips
;
362 GtkWidget
*volume_button
;
363 gboolean syncing_volume
;
366 char *cached_duration
;
367 gboolean cached_playing
;
369 guint sidepane_visibility_notify_id
;
370 guint toolbar_visibility_notify_id
;
371 guint toolbar_style_notify_id
;
372 guint smalldisplay_notify_id
;
374 glong last_small_time
; /* when we last changed small mode */
376 /* Cached copies of the gconf keys.
378 * To avoid race conditions, the only time the keys are actually read is at startup
383 gboolean window_maximised
;
384 gboolean window_small
;
385 gboolean queue_as_sidebar
;
386 gboolean statusbar_hidden
;
391 gint sourcelist_height
;
394 #define RB_SHELL_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), RB_TYPE_SHELL, RBShellPrivate))
396 static GtkActionEntry rb_shell_actions
[] =
398 { "Music", NULL
, N_("_Music") },
399 { "Edit", NULL
, N_("_Edit") },
400 { "View", NULL
, N_("_View") },
401 { "Control", NULL
, N_("_Control") },
402 { "Tools", NULL
, N_("_Tools") },
403 { "Help", NULL
, N_("_Help") },
405 { "MusicImportFolder", GTK_STOCK_OPEN
, N_("_Import Folder..."), "<control>O",
406 N_("Choose folder to be added to the Library"),
407 G_CALLBACK (rb_shell_cmd_add_folder_to_library
) },
408 { "MusicImportFile", GTK_STOCK_FILE
, N_("Import _File..."), NULL
,
409 N_("Choose file to be added to the Library"),
410 G_CALLBACK (rb_shell_cmd_add_file_to_library
) },
411 { "HelpAbout", GTK_STOCK_ABOUT
, N_("_About"), NULL
,
412 N_("Show information about the music player"),
413 G_CALLBACK (rb_shell_cmd_about
) },
414 { "HelpContents", GTK_STOCK_HELP
, N_("_Contents"), "F1",
415 N_("Display music player help"),
416 G_CALLBACK (rb_shell_cmd_contents
) },
417 { "MusicClose", GTK_STOCK_CLOSE
, N_("_Close"), "<control>W",
418 N_("Hide the music player window"),
419 G_CALLBACK (rb_shell_cmd_toggle_visibility
) },
420 { "MusicQuit", GTK_STOCK_QUIT
, N_("_Quit"), "<control>Q",
421 N_("Quit the music player"),
422 G_CALLBACK (rb_shell_cmd_quit
) },
423 { "EditPreferences", GTK_STOCK_PREFERENCES
, N_("Prefere_nces..."), NULL
,
424 N_("Edit music player preferences"),
425 G_CALLBACK (rb_shell_cmd_preferences
) },
426 { "EditPlugins", NULL
, N_("Plu_gins..."), NULL
,
427 N_("Change and configure plugins"),
428 G_CALLBACK (rb_shell_cmd_plugins
) },
429 { "ViewAll", NULL
, N_("Show _All"), "<control>Y",
430 N_("Show all items in this music source"),
431 G_CALLBACK (rb_shell_cmd_view_all
) },
432 { "ViewJumpToPlaying", GTK_STOCK_JUMP_TO
, N_("_Jump to Playing Song"), "<control>J",
433 N_("Scroll the view to the currently playing song"),
434 G_CALLBACK (rb_shell_cmd_current_song
) },
436 static guint rb_shell_n_actions
= G_N_ELEMENTS (rb_shell_actions
);
438 static GtkToggleActionEntry rb_shell_toggle_entries
[] =
440 { "ViewSidePane", NULL
, N_("Side _Pane"), "<control>S",
441 N_("Change the visibility of the side pane"),
442 G_CALLBACK (rb_shell_view_sidepane_changed_cb
), TRUE
},
443 { "ViewToolbar", NULL
, N_("_Toolbar"), NULL
,
444 N_("Change the visibility of the toolbar"),
445 G_CALLBACK (rb_shell_view_toolbar_changed_cb
), TRUE
},
446 { "ViewSmallDisplay", NULL
, N_("_Small Display"), "<control>D",
447 N_("Make the main window smaller"),
448 G_CALLBACK (rb_shell_view_smalldisplay_changed_cb
), },
449 { "ViewPartyMode", NULL
, N_("_Party Mode"), "F11",
450 N_("Change the status of the party mode"),
451 G_CALLBACK (rb_shell_view_party_mode_changed_cb
), FALSE
},
452 { "ViewQueueAsSidebar", NULL
, N_("Play _Queue as Side Pane"), "<control>K",
453 N_("Change whether the queue is visible as a source or a sidebar"),
454 G_CALLBACK (rb_shell_view_queue_as_sidebar_changed_cb
) },
455 { "ViewStatusbar", NULL
, N_("S_tatusbar"), NULL
,
456 N_("Change the visibility of the statusbar"),
457 G_CALLBACK (rb_shell_view_statusbar_changed_cb
), TRUE
}
459 static guint rb_shell_n_toggle_entries
= G_N_ELEMENTS (rb_shell_toggle_entries
);
462 rb_shell_class_init (RBShellClass
*klass
)
464 GObjectClass
*object_class
= (GObjectClass
*) klass
;
466 object_class
->set_property
= rb_shell_set_property
;
467 object_class
->get_property
= rb_shell_get_property
;
468 object_class
->finalize
= rb_shell_finalize
;
469 object_class
->constructor
= rb_shell_constructor
;
471 g_object_class_install_property (object_class
,
473 g_param_spec_int ("argc",
477 0, G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
));
479 g_object_class_install_property (object_class
,
481 g_param_spec_pointer ("argv",
484 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
));
486 g_object_class_install_property (object_class
,
487 PROP_NO_REGISTRATION
,
488 g_param_spec_boolean ("no-registration",
490 "Whether or not to register",
492 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
));
494 g_object_class_install_property (object_class
,
496 g_param_spec_boolean ("no-update",
498 "Whether or not to update the library",
500 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
));
502 g_object_class_install_property (object_class
,
504 g_param_spec_boolean ("dry-run",
506 "Whether or not this is a dry run",
508 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
));
510 g_object_class_install_property (object_class
,
512 g_param_spec_string ("rhythmdb-file",
514 "The RhythmDB file to use",
515 #ifdef WITH_RHYTHMDB_TREE
517 #elif defined(WITH_RHYTHMDB_GDA)
518 "rhythmdb.sqlite", /* FIXME: correct extension? */
520 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
));
523 g_object_class_install_property (object_class
,
525 g_param_spec_string ("playlists-file",
527 "The playlists file to use",
529 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
));
533 g_object_class_install_property (object_class
,
534 PROP_SELECTED_SOURCE
,
535 g_param_spec_object ("selected-source",
537 "Source which is currently selected",
541 g_object_class_install_property (object_class
,
543 g_param_spec_object ("db",
549 g_object_class_install_property (object_class
,
551 g_param_spec_object ("ui-manager",
553 "GtkUIManager object",
557 g_object_class_install_property (object_class
,
559 g_param_spec_object ("clipboard",
561 "RBShellClipboard object",
562 RB_TYPE_SHELL_CLIPBOARD
,
564 g_object_class_install_property (object_class
,
565 PROP_PLAYLIST_MANAGER
,
566 g_param_spec_object ("playlist-manager",
568 "RBPlaylistManager object",
569 RB_TYPE_PLAYLIST_MANAGER
,
571 g_object_class_install_property (object_class
,
573 g_param_spec_object ("shell-player",
575 "RBShellPlayer object",
576 RB_TYPE_SHELL_PLAYER
,
578 g_object_class_install_property (object_class
,
579 PROP_REMOVABLE_MEDIA_MANAGER
,
580 g_param_spec_object ("removable-media-manager",
581 "RBRemovableMediaManager",
582 "RBRemovableMediaManager object",
583 RB_TYPE_REMOVABLE_MEDIA_MANAGER
,
585 g_object_class_install_property (object_class
,
587 g_param_spec_object ("window",
592 g_object_class_install_property (object_class
,
594 g_param_spec_object ("prefs",
595 "RBShellPreferences",
596 "RBShellPreferences object",
597 RB_TYPE_SHELL_PREFERENCES
,
599 g_object_class_install_property (object_class
,
601 g_param_spec_object ("queue-source",
604 RB_TYPE_PLAY_QUEUE_SOURCE
,
606 g_object_class_install_property (object_class
,
608 g_param_spec_object ("proxy-config",
610 "HTTP proxy configuration",
611 RB_TYPE_PROXY_CONFIG
,
613 g_object_class_install_property (object_class
,
615 g_param_spec_object ("library-source",
618 RB_TYPE_LIBRARY_SOURCE
,
620 g_object_class_install_property (object_class
,
621 PROP_SOURCELIST_MODEL
,
622 g_param_spec_object ("sourcelist-model",
625 RB_TYPE_SOURCELIST_MODEL
,
628 g_object_class_install_property (object_class
,
630 g_param_spec_boolean ("visibility",
632 "Current window visibility",
636 rb_shell_signals
[VISIBILITY_CHANGED
] =
637 g_signal_new ("visibility_changed",
638 G_OBJECT_CLASS_TYPE (object_class
),
640 G_STRUCT_OFFSET (RBShellClass
, visibility_changed
),
642 g_cclosure_marshal_VOID__BOOLEAN
,
647 rb_shell_signals
[CREATE_SONG_INFO
] =
648 g_signal_new ("create_song_info",
649 G_OBJECT_CLASS_TYPE (object_class
),
651 G_STRUCT_OFFSET (RBShellClass
, create_song_info
),
653 rb_marshal_VOID__OBJECT_BOOLEAN
,
656 RB_TYPE_SONG_INFO
, G_TYPE_BOOLEAN
);
658 g_type_class_add_private (klass
, sizeof (RBShellPrivate
));
662 rb_shell_init (RBShell
*shell
)
664 shell
->priv
= RB_SHELL_GET_PRIVATE (shell
);
668 rb_shell_session_init (shell
);
670 eel_gconf_monitor_add (CONF_PREFIX
);
674 rb_shell_set_property (GObject
*object
,
679 RBShell
*shell
= RB_SHELL (object
);
684 shell
->priv
->argc
= g_value_get_int (value
);
687 shell
->priv
->argv
= g_value_get_pointer (value
);
689 case PROP_NO_REGISTRATION
:
690 shell
->priv
->no_registration
= g_value_get_boolean (value
);
693 shell
->priv
->no_update
= g_value_get_boolean (value
);
696 shell
->priv
->dry_run
= g_value_get_boolean (value
);
697 if (shell
->priv
->dry_run
)
698 shell
->priv
->no_registration
= TRUE
;
700 case PROP_RHYTHMDB_FILE
:
701 g_free (shell
->priv
->rhythmdb_file
);
702 shell
->priv
->rhythmdb_file
= g_value_dup_string (value
);
704 case PROP_PLAYLISTS_FILE
:
705 g_free (shell
->priv
->playlists_file
);
706 shell
->priv
->playlists_file
= g_value_dup_string (value
);
708 case PROP_VISIBILITY
:
709 rb_shell_set_visibility (shell
, g_value_get_boolean (value
), FALSE
);
712 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
718 rb_shell_get_property (GObject
*object
,
723 RBShell
*shell
= RB_SHELL (object
);
728 g_value_set_int (value
, shell
->priv
->argc
);
731 g_value_set_pointer (value
, shell
->priv
->argv
);
733 case PROP_NO_REGISTRATION
:
734 g_value_set_boolean (value
, shell
->priv
->no_registration
);
737 g_value_set_boolean (value
, shell
->priv
->no_update
);
740 g_value_set_boolean (value
, shell
->priv
->dry_run
);
742 case PROP_RHYTHMDB_FILE
:
743 g_value_set_string (value
, shell
->priv
->rhythmdb_file
);
745 case PROP_PLAYLISTS_FILE
:
746 g_value_set_string (value
, shell
->priv
->playlists_file
);
749 g_value_set_object (value
, shell
->priv
->db
);
751 case PROP_UI_MANAGER
:
752 g_value_set_object (value
, shell
->priv
->ui_manager
);
755 g_value_set_object (value
, shell
->priv
->clipboard_shell
);
757 case PROP_PLAYLIST_MANAGER
:
758 g_value_set_object (value
, shell
->priv
->playlist_manager
);
760 case PROP_SHELL_PLAYER
:
761 g_value_set_object (value
, shell
->priv
->player_shell
);
763 case PROP_REMOVABLE_MEDIA_MANAGER
:
764 g_value_set_object (value
, shell
->priv
->removable_media_manager
);
766 case PROP_SELECTED_SOURCE
:
767 g_value_set_object (value
, shell
->priv
->selected_source
);
770 g_value_set_object (value
, shell
->priv
->window
);
773 g_value_set_object (value
, shell
->priv
->prefs
);
775 case PROP_QUEUE_SOURCE
:
776 g_value_set_object (value
, shell
->priv
->queue_source
);
778 case PROP_PROXY_CONFIG
:
779 g_value_set_object (value
, shell
->priv
->proxy_config
);
781 case PROP_LIBRARY_SOURCE
:
782 g_value_set_object (value
, shell
->priv
->library_source
);
784 case PROP_SOURCELIST_MODEL
:
786 GtkTreeModel
*model
= NULL
;
788 g_object_get (shell
->priv
->sourcelist
, "model", &model
, NULL
);
789 g_value_set_object (value
, model
);
790 g_object_unref (model
);
793 case PROP_VISIBILITY
:
794 g_value_set_boolean (value
, rb_shell_get_visibility (shell
));
797 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
803 rb_shell_sync_state (RBShell
*shell
)
805 if (shell
->priv
->dry_run
) {
806 rb_debug ("in dry-run mode, not syncing state");
810 if (!shell
->priv
->load_complete
) {
811 rb_debug ("load incomplete, not syncing state");
815 rb_debug ("saving playlists");
816 rb_playlist_manager_save_playlists (shell
->priv
->playlist_manager
,
819 rb_debug ("saving db");
820 rhythmdb_save (shell
->priv
->db
);
825 idle_save_rhythmdb (RBShell
*shell
)
827 rhythmdb_save (shell
->priv
->db
);
829 shell
->priv
->save_db_id
= 0;
835 idle_save_playlist_manager (RBShell
*shell
)
837 GDK_THREADS_ENTER ();
838 rb_playlist_manager_save_playlists (shell
->priv
->playlist_manager
,
840 GDK_THREADS_LEAVE ();
846 rb_shell_shutdown (RBShell
*shell
)
850 if (shell
->priv
->shutting_down
)
852 shell
->priv
->shutting_down
= TRUE
;
854 /* Hide the main window and tray icon as soon as possible */
855 display
= gtk_widget_get_display (shell
->priv
->window
);
856 gtk_widget_hide (shell
->priv
->window
);
857 gtk_widget_hide (GTK_WIDGET (shell
->priv
->tray_icon
));
858 gdk_display_sync (display
);
862 rb_shell_finalize (GObject
*object
)
864 RBShell
*shell
= RB_SHELL (object
);
866 rb_debug ("Finalizing shell");
868 rb_shell_player_stop (shell
->priv
->player_shell
);
870 eel_gconf_monitor_remove (CONF_PREFIX
);
871 eel_gconf_notification_remove (shell
->priv
->sidepane_visibility_notify_id
);
872 eel_gconf_notification_remove (shell
->priv
->toolbar_visibility_notify_id
);
873 eel_gconf_notification_remove (shell
->priv
->toolbar_style_notify_id
);
874 eel_gconf_notification_remove (shell
->priv
->smalldisplay_notify_id
);
876 g_list_free (shell
->priv
->supported_media_extensions
);
878 gtk_widget_destroy (GTK_WIDGET (shell
->priv
->tray_icon
));
880 if (shell
->priv
->save_playlist_id
> 0) {
881 g_source_remove (shell
->priv
->save_playlist_id
);
882 shell
->priv
->save_playlist_id
= 0;
885 if (shell
->priv
->save_db_id
> 0) {
886 g_source_remove (shell
->priv
->save_db_id
);
887 shell
->priv
->save_db_id
= 0;
890 if (shell
->priv
->queue_sidebar
!= NULL
) {
891 g_object_unref (shell
->priv
->queue_sidebar
);
894 rb_debug ("shutting down playlist manager");
895 rb_playlist_manager_shutdown (shell
->priv
->playlist_manager
);
897 rb_debug ("unreffing playlist manager");
898 g_object_unref (G_OBJECT (shell
->priv
->playlist_manager
));
900 rb_debug ("unreffing removable media manager");
901 g_object_unref (G_OBJECT (shell
->priv
->removable_media_manager
));
903 g_object_unref (G_OBJECT (shell
->priv
->proxy_config
));
905 rb_debug ("unreffing clipboard shell");
906 g_object_unref (G_OBJECT (shell
->priv
->clipboard_shell
));
908 rb_debug ("destroying prefs");
909 if (shell
->priv
->prefs
!= NULL
)
910 gtk_widget_destroy (shell
->priv
->prefs
);
912 rb_debug ("destroying tooltips");
913 gtk_object_destroy (GTK_OBJECT (shell
->priv
->tooltips
));
915 g_free (shell
->priv
->rhythmdb_file
);
917 g_free (shell
->priv
->playlists_file
);
919 rb_debug ("destroying window");
920 gtk_widget_destroy (shell
->priv
->window
);
922 g_list_free (shell
->priv
->sources
);
923 shell
->priv
->sources
= NULL
;
925 g_hash_table_destroy (shell
->priv
->sources_hash
);
927 rb_debug ("shutting down DB");
928 rhythmdb_shutdown (shell
->priv
->db
);
930 rb_debug ("unreffing DB");
931 g_object_unref (G_OBJECT (shell
->priv
->db
));
933 ((GObjectClass
*)rb_shell_parent_class
)->finalize (G_OBJECT (shell
));
935 rb_debug ("shell shutdown complete");
939 rb_shell_new (int argc
,
941 gboolean no_registration
,
950 /* set default playlist name, if none supplied */
952 pathname
= g_strdup (playlists
);
954 pathname
= g_build_filename (rb_dot_dir (), "playlists.xml", NULL
);
956 s
= g_object_new (RB_TYPE_SHELL
, "argc", argc
, "argv", argv
,
957 "no-registration", no_registration
,
958 "no-update", no_update
,
959 "dry-run", dry_run
, "rhythmdb-file", rhythmdb
,
960 "playlists-file", pathname
, NULL
);
967 construct_db (RBShell
*shell
)
971 /* Initialize the database */
972 rb_debug ("creating database object");
973 rb_profile_start ("creating database object");
975 if (shell
->priv
->rhythmdb_file
)
976 pathname
= g_strdup (shell
->priv
->rhythmdb_file
);
978 pathname
= g_build_filename (rb_dot_dir (), "rhythmdb.xml", NULL
);
980 #ifdef WITH_RHYTHMDB_TREE
981 shell
->priv
->db
= rhythmdb_tree_new (pathname
);
982 #elif defined(WITH_RHYTHMDB_GDA)
983 shell
->priv
->db
= rhythmdb_gda_new (pathname
);
987 if (shell
->priv
->dry_run
)
988 g_object_set (G_OBJECT (shell
->priv
->db
), "dry-run", TRUE
, NULL
);
989 if (shell
->priv
->no_update
)
990 g_object_set (G_OBJECT (shell
->priv
->db
), "no-update", TRUE
, NULL
);
992 g_signal_connect_object (G_OBJECT (shell
->priv
->db
), "load-complete",
993 G_CALLBACK (rb_shell_load_complete_cb
), shell
,
996 rb_profile_end ("creating database object");
1000 construct_widgets (RBShell
*shell
)
1004 rb_profile_start ("constructing widgets");
1007 win
= GTK_WINDOW (gtk_window_new (GTK_WINDOW_TOPLEVEL
));
1008 gtk_window_set_title (win
, _("Music Player"));
1010 shell
->priv
->window
= GTK_WIDGET (win
);
1011 shell
->priv
->iconified
= FALSE
;
1012 g_signal_connect_object (G_OBJECT (win
), "window-state-event",
1013 G_CALLBACK (rb_shell_window_state_cb
),
1016 g_signal_connect_object (G_OBJECT (win
), "configure-event",
1017 G_CALLBACK (rb_shell_window_configure_cb
),
1020 /* connect after, so that things can affect behaviour */
1021 g_signal_connect_object (G_OBJECT (win
), "delete_event",
1022 G_CALLBACK (rb_shell_window_delete_cb
),
1023 shell
, G_CONNECT_AFTER
);
1025 rb_debug ("shell: initializing shell services");
1027 shell
->priv
->ui_manager
= gtk_ui_manager_new ();
1028 shell
->priv
->source_ui_merge_id
= gtk_ui_manager_new_merge_id (shell
->priv
->ui_manager
);
1030 shell
->priv
->player_shell
= rb_shell_player_new (shell
->priv
->db
,
1031 shell
->priv
->ui_manager
,
1032 shell
->priv
->actiongroup
);
1033 g_signal_connect_object (G_OBJECT (shell
->priv
->player_shell
),
1034 "playing-source-changed",
1035 G_CALLBACK (rb_shell_playing_source_changed_cb
),
1037 g_signal_connect_object (G_OBJECT (shell
->priv
->player_shell
),
1038 "playing-song-changed",
1039 G_CALLBACK (rb_shell_playing_entry_changed_cb
),
1041 g_signal_connect_object (G_OBJECT (shell
->priv
->player_shell
),
1042 "notify::playing-from-queue",
1043 G_CALLBACK (rb_shell_playing_from_queue_cb
),
1045 g_signal_connect_object (G_OBJECT (shell
->priv
->player_shell
),
1046 "window_title_changed",
1047 G_CALLBACK (rb_shell_player_window_title_changed_cb
),
1049 g_signal_connect_object (G_OBJECT (shell
->priv
->player_shell
),
1051 G_CALLBACK (rb_shell_player_elapsed_changed_cb
),
1053 shell
->priv
->clipboard_shell
= rb_shell_clipboard_new (shell
->priv
->actiongroup
,
1054 shell
->priv
->ui_manager
,
1056 shell
->priv
->source_header
= rb_source_header_new (shell
->priv
->ui_manager
,
1057 shell
->priv
->actiongroup
);
1058 gtk_widget_show_all (GTK_WIDGET (shell
->priv
->source_header
));
1060 shell
->priv
->paned
= gtk_hpaned_new ();
1062 shell
->priv
->sourcelist
= rb_sourcelist_new (shell
);
1063 gtk_widget_show_all (shell
->priv
->sourcelist
);
1064 g_signal_connect_object (G_OBJECT (shell
->priv
->sourcelist
), "drop_received",
1065 G_CALLBACK (sourcelist_drag_received_cb
), shell
, 0);
1066 g_signal_connect_object (G_OBJECT (shell
->priv
->sourcelist
), "source_activated",
1067 G_CALLBACK (source_activated_cb
), shell
, 0);
1068 g_signal_connect_object (G_OBJECT (shell
->priv
->sourcelist
), "show_popup",
1069 G_CALLBACK (rb_shell_show_popup_cb
), shell
, 0);
1071 shell
->priv
->statusbar
= rb_statusbar_new (shell
->priv
->db
,
1072 shell
->priv
->ui_manager
);
1073 g_object_set (shell
->priv
->player_shell
, "statusbar", shell
->priv
->statusbar
, NULL
);
1074 gtk_widget_show (GTK_WIDGET (shell
->priv
->statusbar
));
1076 g_signal_connect_object (G_OBJECT (shell
->priv
->sourcelist
), "selected",
1077 G_CALLBACK (source_selected_cb
), shell
, 0);
1079 shell
->priv
->notebook
= gtk_notebook_new ();
1080 gtk_widget_show (shell
->priv
->notebook
);
1081 gtk_notebook_set_show_tabs (GTK_NOTEBOOK (shell
->priv
->notebook
), FALSE
);
1082 gtk_notebook_set_show_border (GTK_NOTEBOOK (shell
->priv
->notebook
), FALSE
);
1083 g_signal_connect_object (G_OBJECT (shell
->priv
->sourcelist
),
1085 G_CALLBACK (paned_size_allocate_cb
),
1088 shell
->priv
->queue_source
= RB_PLAYLIST_SOURCE (rb_play_queue_source_new (shell
));
1089 g_object_set (G_OBJECT(shell
->priv
->player_shell
), "queue-source", shell
->priv
->queue_source
, NULL
);
1090 g_object_set (G_OBJECT(shell
->priv
->clipboard_shell
), "queue-source", shell
->priv
->queue_source
, NULL
);
1091 rb_shell_append_source (shell
, RB_SOURCE (shell
->priv
->queue_source
), NULL
);
1092 g_object_get (shell
->priv
->queue_source
, "sidebar", &shell
->priv
->queue_sidebar
, NULL
);
1093 gtk_widget_show_all (shell
->priv
->queue_sidebar
);
1094 gtk_widget_set_no_show_all (shell
->priv
->queue_sidebar
, TRUE
);
1096 /* places for plugins to put UI */
1097 shell
->priv
->top_container
= GTK_BOX (gtk_vbox_new (FALSE
, 0));
1098 shell
->priv
->bottom_container
= GTK_BOX (gtk_vbox_new (FALSE
, 0));
1099 shell
->priv
->sidebar_container
= GTK_BOX (gtk_vbox_new (FALSE
, 0));
1101 /* set up sidebars */
1102 shell
->priv
->paned
= gtk_hpaned_new ();
1104 GtkWidget
*vbox2
= gtk_vbox_new (FALSE
, 0);
1106 shell
->priv
->queue_paned
= gtk_vpaned_new ();
1107 gtk_paned_pack1 (GTK_PANED (shell
->priv
->queue_paned
),
1108 shell
->priv
->sourcelist
,
1110 gtk_paned_pack2 (GTK_PANED (shell
->priv
->queue_paned
),
1111 shell
->priv
->queue_sidebar
,
1113 gtk_container_child_set (GTK_CONTAINER (shell
->priv
->queue_paned
),
1114 GTK_WIDGET (shell
->priv
->sourcelist
),
1118 gtk_box_pack_start (GTK_BOX (vbox2
),
1119 GTK_WIDGET (shell
->priv
->source_header
),
1121 gtk_box_pack_start (GTK_BOX (vbox2
),
1122 shell
->priv
->notebook
,
1125 gtk_box_pack_start_defaults (shell
->priv
->sidebar_container
, shell
->priv
->queue_paned
);
1126 gtk_paned_pack1 (GTK_PANED (shell
->priv
->paned
),
1127 GTK_WIDGET (shell
->priv
->sidebar_container
),
1129 gtk_paned_pack2 (GTK_PANED (shell
->priv
->paned
),
1132 gtk_widget_show (vbox2
);
1135 g_signal_connect_object (G_OBJECT (shell
->priv
->queue_paned
),
1137 G_CALLBACK (sidebar_paned_size_allocate_cb
),
1139 gtk_widget_show (shell
->priv
->paned
);
1141 shell
->priv
->main_vbox
= gtk_vbox_new (FALSE
, 0);
1142 gtk_container_set_border_width (GTK_CONTAINER (shell
->priv
->main_vbox
), 0);
1143 gtk_box_pack_start (GTK_BOX (shell
->priv
->main_vbox
), GTK_WIDGET (shell
->priv
->player_shell
), FALSE
, TRUE
, 6);
1144 gtk_widget_show (GTK_WIDGET (shell
->priv
->player_shell
));
1146 gtk_box_pack_start (GTK_BOX (shell
->priv
->main_vbox
), GTK_WIDGET (shell
->priv
->top_container
), FALSE
, TRUE
, 0);
1147 gtk_box_pack_start (GTK_BOX (shell
->priv
->main_vbox
), shell
->priv
->paned
, TRUE
, TRUE
, 0);
1148 gtk_box_pack_start (GTK_BOX (shell
->priv
->main_vbox
), GTK_WIDGET (shell
->priv
->bottom_container
), FALSE
, TRUE
, 0);
1149 gtk_box_pack_start (GTK_BOX (shell
->priv
->main_vbox
), GTK_WIDGET (shell
->priv
->statusbar
), FALSE
, TRUE
, 0);
1150 gtk_widget_show_all (shell
->priv
->main_vbox
);
1152 gtk_container_add (GTK_CONTAINER (win
), shell
->priv
->main_vbox
);
1154 shell
->priv
->proxy_config
= rb_proxy_config_new ();
1156 rb_profile_end ("constructing widgets");
1160 construct_sources (RBShell
*shell
)
1162 rb_profile_start ("constructing sources");
1164 shell
->priv
->library_source
= RB_LIBRARY_SOURCE (rb_library_source_new (shell
));
1165 rb_shell_append_source (shell
, RB_SOURCE (shell
->priv
->library_source
), NULL
);
1166 shell
->priv
->podcast_source
= RB_PODCAST_SOURCE (rb_podcast_source_new (shell
));
1167 rb_shell_append_source (shell
, RB_SOURCE (shell
->priv
->podcast_source
), NULL
);
1168 shell
->priv
->missing_files_source
= rb_missing_files_source_new (shell
, shell
->priv
->library_source
);
1169 rb_shell_append_source (shell
, shell
->priv
->missing_files_source
, RB_SOURCE (shell
->priv
->library_source
));
1170 shell
->priv
->import_errors_source
= rb_import_errors_source_new (shell
, shell
->priv
->library_source
);
1171 rb_shell_append_source (shell
, shell
->priv
->import_errors_source
, RB_SOURCE (shell
->priv
->library_source
));
1173 /* Initialize playlist manager */
1174 rb_debug ("shell: creating playlist manager");
1175 shell
->priv
->playlist_manager
= rb_playlist_manager_new (shell
,
1176 RB_SOURCELIST (shell
->priv
->sourcelist
), shell
->priv
->playlists_file
);
1178 g_object_set (G_OBJECT(shell
->priv
->clipboard_shell
), "playlist-manager", shell
->priv
->playlist_manager
, NULL
);
1180 g_signal_connect_object (G_OBJECT (shell
->priv
->playlist_manager
), "playlist_added",
1181 G_CALLBACK (rb_shell_playlist_added_cb
), shell
, 0);
1182 g_signal_connect_object (G_OBJECT (shell
->priv
->playlist_manager
), "playlist_created",
1183 G_CALLBACK (rb_shell_playlist_created_cb
), shell
, 0);
1185 /* Initialize removable media manager */
1186 rb_debug ("shell: creating removable media manager");
1187 shell
->priv
->removable_media_manager
= rb_removable_media_manager_new (shell
,
1188 RB_SOURCELIST (shell
->priv
->sourcelist
));
1190 g_signal_connect_object (G_OBJECT (shell
->priv
->removable_media_manager
), "medium_added",
1191 G_CALLBACK (rb_shell_medium_added_cb
), shell
, 0);
1192 g_signal_connect_object (G_OBJECT (shell
->priv
->removable_media_manager
), "transfer-progress",
1193 G_CALLBACK (rb_shell_transfer_progress_cb
), shell
, 0);
1195 rb_profile_end ("constructing sources");
1199 construct_load_ui (RBShell
*shell
)
1204 GtkToolItem
*tool_item
;
1205 GError
*error
= NULL
;
1207 rb_debug ("shell: loading ui");
1208 rb_profile_start ("loading ui");
1210 gtk_ui_manager_insert_action_group (shell
->priv
->ui_manager
,
1211 shell
->priv
->actiongroup
, 0);
1212 gtk_ui_manager_add_ui_from_file (shell
->priv
->ui_manager
,
1213 rb_file ("rhythmbox-ui.xml"), &error
);
1215 gtk_ui_manager_ensure_update (shell
->priv
->ui_manager
);
1216 gtk_window_add_accel_group (GTK_WINDOW (shell
->priv
->window
),
1217 gtk_ui_manager_get_accel_group (shell
->priv
->ui_manager
));
1218 menubar
= gtk_ui_manager_get_widget (shell
->priv
->ui_manager
, "/MenuBar");
1220 gtk_box_pack_start (GTK_BOX (shell
->priv
->main_vbox
), menubar
, FALSE
, FALSE
, 0);
1221 gtk_box_reorder_child (GTK_BOX (shell
->priv
->main_vbox
), menubar
, 0);
1223 hbox
= gtk_hbox_new (FALSE
, 0);
1224 gtk_box_pack_start (GTK_BOX (shell
->priv
->main_vbox
), hbox
, FALSE
, FALSE
, 0);
1225 gtk_box_reorder_child (GTK_BOX (shell
->priv
->main_vbox
), hbox
, 1);
1227 toolbar
= gtk_ui_manager_get_widget (shell
->priv
->ui_manager
, "/ToolBar");
1228 gtk_box_pack_start_defaults (GTK_BOX (hbox
), toolbar
);
1230 shell
->priv
->volume_button
= bacon_volume_button_new (GTK_ICON_SIZE_LARGE_TOOLBAR
,
1232 g_signal_connect (shell
->priv
->volume_button
, "value-changed",
1233 G_CALLBACK (rb_shell_volume_widget_changed_cb
),
1235 g_signal_connect (shell
->priv
->player_shell
, "notify::volume",
1236 G_CALLBACK (rb_shell_player_volume_changed_cb
),
1238 rb_shell_player_volume_changed_cb (shell
->priv
->player_shell
, NULL
, shell
);
1240 tool_item
= gtk_tool_item_new ();
1241 gtk_tool_item_set_expand (tool_item
, TRUE
);
1242 gtk_widget_show (GTK_WIDGET (tool_item
));
1243 gtk_toolbar_insert (GTK_TOOLBAR (toolbar
), tool_item
, -1);
1245 tool_item
= gtk_tool_item_new ();
1246 gtk_container_add (GTK_CONTAINER (tool_item
), shell
->priv
->volume_button
);
1247 gtk_widget_show_all (GTK_WIDGET (tool_item
));
1248 gtk_toolbar_insert (GTK_TOOLBAR (toolbar
), tool_item
, -1);
1250 gtk_widget_show (hbox
);
1252 shell
->priv
->tooltips
= gtk_tooltips_new ();
1253 gtk_tooltips_enable (shell
->priv
->tooltips
);
1255 gtk_tooltips_set_tip (GTK_TOOLTIPS (shell
->priv
->tooltips
),
1256 GTK_WIDGET (shell
->priv
->volume_button
),
1257 _("Change the music volume"), NULL
);
1259 if (error
!= NULL
) {
1260 g_warning ("Couldn't merge %s: %s",
1261 rb_file ("rhythmbox-ui.xml"), error
->message
);
1262 g_clear_error (&error
);
1265 rb_profile_end ("loading ui");
1269 _scan_idle (RBShell
*shell
)
1271 GDK_THREADS_ENTER ();
1272 rb_removable_media_manager_scan (shell
->priv
->removable_media_manager
);
1273 GDK_THREADS_LEAVE ();
1278 rb_shell_constructor (GType type
,
1279 guint n_construct_properties
,
1280 GObjectConstructParam
*construct_properties
)
1284 shell
= RB_SHELL (((GObjectClass
*)rb_shell_parent_class
)
1285 ->constructor (type
, n_construct_properties
, construct_properties
));
1287 rb_debug ("Constructing shell");
1288 rb_profile_start ("constructing shell");
1290 shell
->priv
->actiongroup
= gtk_action_group_new ("MainActions");
1291 gtk_action_group_set_translation_domain (shell
->priv
->actiongroup
,
1293 gtk_action_group_add_actions (shell
->priv
->actiongroup
,
1295 rb_shell_n_actions
, shell
);
1296 gtk_action_group_add_toggle_actions (shell
->priv
->actiongroup
,
1297 rb_shell_toggle_entries
,
1298 rb_shell_n_toggle_entries
,
1301 construct_db (shell
);
1303 /* initialize shell services */
1304 construct_widgets (shell
);
1306 rb_debug ("shell: setting up tray icon");
1307 tray_destroy_cb (NULL
, shell
);
1309 rb_debug ("shell: adding gconf notification");
1311 shell
->priv
->sidepane_visibility_notify_id
=
1312 eel_gconf_notification_add (CONF_UI_SIDEPANE_HIDDEN
,
1313 (GConfClientNotifyFunc
) sidepane_visibility_changed_cb
,
1315 shell
->priv
->toolbar_visibility_notify_id
=
1316 eel_gconf_notification_add (CONF_UI_TOOLBAR_HIDDEN
,
1317 (GConfClientNotifyFunc
) toolbar_state_changed_cb
,
1319 shell
->priv
->toolbar_style_notify_id
=
1320 eel_gconf_notification_add (CONF_UI_TOOLBAR_STYLE
,
1321 (GConfClientNotifyFunc
) toolbar_state_changed_cb
,
1323 shell
->priv
->smalldisplay_notify_id
=
1324 eel_gconf_notification_add (CONF_UI_SMALL_DISPLAY
,
1325 (GConfClientNotifyFunc
) smalldisplay_changed_cb
,
1328 /* read the cached copies of the gconf keys */
1329 shell
->priv
->window_width
= eel_gconf_get_integer (CONF_STATE_WINDOW_WIDTH
);
1330 shell
->priv
->window_height
= eel_gconf_get_integer (CONF_STATE_WINDOW_HEIGHT
);
1331 shell
->priv
->small_width
= eel_gconf_get_integer (CONF_STATE_SMALL_WIDTH
);
1332 shell
->priv
->window_maximised
= eel_gconf_get_boolean (CONF_STATE_WINDOW_MAXIMIZED
);
1333 shell
->priv
->window_small
= eel_gconf_get_boolean (CONF_UI_SMALL_DISPLAY
);
1334 shell
->priv
->queue_as_sidebar
= eel_gconf_get_boolean (CONF_UI_QUEUE_AS_SIDEBAR
);
1335 shell
->priv
->window_x
= eel_gconf_get_integer (CONF_STATE_WINDOW_X_POSITION
);
1336 shell
->priv
->window_y
= eel_gconf_get_integer (CONF_STATE_WINDOW_Y_POSITION
);
1337 shell
->priv
->paned_position
= eel_gconf_get_integer (CONF_STATE_PANED_POSITION
);
1338 shell
->priv
->sourcelist_height
= eel_gconf_get_integer (CONF_STATE_SOURCELIST_HEIGHT
);
1339 shell
->priv
->statusbar_hidden
= eel_gconf_get_boolean (CONF_UI_STATUSBAR_HIDDEN
);
1341 rb_debug ("shell: syncing with gconf");
1342 rb_shell_sync_sidepane_visibility (shell
);
1343 rb_shell_sync_pane_visibility (shell
);
1345 g_signal_connect_object (G_OBJECT (shell
->priv
->db
), "save-error",
1346 G_CALLBACK (rb_shell_db_save_error_cb
), shell
, 0);
1347 g_signal_connect_object (G_OBJECT (shell
->priv
->db
), "entry-added",
1348 G_CALLBACK (rb_shell_db_entry_added_cb
), shell
, 0);
1350 construct_sources (shell
);
1352 construct_load_ui (shell
);
1354 rb_shell_sync_window_state (shell
, FALSE
);
1355 rb_shell_sync_smalldisplay (shell
);
1356 rb_shell_sync_party_mode (shell
);
1357 rb_shell_sync_toolbar_state (shell
);
1359 rb_shell_select_source (shell
, RB_SOURCE (shell
->priv
->library_source
));
1361 rb_plugins_engine_init (shell
);
1363 g_idle_add ((GSourceFunc
)_scan_idle
, shell
);
1366 rb_debug ("loading database");
1367 rhythmdb_load (shell
->priv
->db
);
1369 rb_debug ("shell: syncing window state");
1370 rb_shell_sync_paned (shell
);
1371 gtk_widget_show_all (GTK_WIDGET (shell
->priv
->tray_icon
));
1373 /* Stop here if this is the first time. */
1374 if (!eel_gconf_get_boolean (CONF_FIRST_TIME
)) {
1376 druid
= rb_druid_new (shell
->priv
->db
);
1377 g_signal_connect (G_OBJECT (druid
),
1379 G_CALLBACK (rb_shell_druid_response_cb
),
1382 gtk_widget_show_all (GTK_WIDGET (druid
));
1384 rb_shell_set_visibility (shell
, eel_gconf_get_boolean (CONF_STATE_WINDOW_VISIBLE
), TRUE
);
1385 gdk_notify_startup_complete ();
1388 /* focus play if small, the entry view if not */
1389 if (shell
->priv
->window_small
) {
1390 GtkWidget
*play_button
;
1392 play_button
= gtk_ui_manager_get_widget (shell
->priv
->ui_manager
, "/ToolBar/Play");
1393 gtk_widget_grab_focus (play_button
);
1397 view
= rb_source_get_entry_view (RB_SOURCE (shell
->priv
->library_source
));
1398 gtk_widget_grab_focus (GTK_WIDGET (view
));
1401 rb_profile_end ("constructing shell");
1403 return G_OBJECT (shell
);
1406 /* Based on a function found in wnck */
1408 set_icon_geometry (GdkWindow
*window
,
1415 Display
*dpy
= gdk_x11_drawable_get_xdisplay (window
);
1422 XChangeProperty (dpy
,
1423 GDK_WINDOW_XID (window
),
1424 gdk_x11_get_xatom_by_name_for_display (gdk_drawable_get_display (window
),
1425 "_NET_WM_ICON_GEOMETRY"),
1426 XA_CARDINAL
, 32, PropModeReplace
,
1427 (guchar
*)&data
, 4);
1431 rb_shell_window_state_cb (GtkWidget
*widget
,
1432 GdkEventWindowState
*event
,
1435 shell
->priv
->iconified
= ((event
->new_window_state
& GDK_WINDOW_STATE_ICONIFIED
) != 0);
1437 if (event
->changed_mask
& (GDK_WINDOW_STATE_WITHDRAWN
| GDK_WINDOW_STATE_ICONIFIED
)) {
1438 g_signal_emit (shell
, rb_shell_signals
[VISIBILITY_CHANGED
], 0,
1439 rb_shell_get_visibility (shell
));
1442 /* don't save maximized state when is hidden */
1443 if (!GTK_WIDGET_VISIBLE(shell
->priv
->window
))
1446 if (event
->changed_mask
& GDK_WINDOW_STATE_MAXIMIZED
) {
1447 gboolean maximised
= ((event
->new_window_state
& GDK_WINDOW_STATE_MAXIMIZED
) != 0);
1449 gtk_statusbar_set_has_resize_grip (GTK_STATUSBAR (shell
->priv
->statusbar
),
1451 if (!shell
->priv
->window_small
) {
1452 shell
->priv
->window_maximised
= maximised
;
1453 eel_gconf_set_boolean (CONF_STATE_WINDOW_MAXIMIZED
,
1454 shell
->priv
->window_maximised
);
1456 rb_shell_sync_window_state (shell
, TRUE
);
1457 rb_shell_sync_paned (shell
);
1464 rb_shell_get_visibility (RBShell
*shell
)
1466 GdkWindowState state
;
1468 if (!GTK_WIDGET_REALIZED (shell
->priv
->window
))
1470 if (shell
->priv
->iconified
)
1473 state
= gdk_window_get_state (GTK_WIDGET (shell
->priv
->window
)->window
);
1474 if (state
& (GDK_WINDOW_STATE_WITHDRAWN
| GDK_WINDOW_STATE_ICONIFIED
))
1481 idle_hide_mainwindow (gpointer data
)
1483 RBShell
*shell
= RB_SHELL (data
);
1485 GDK_THREADS_ENTER ();
1487 gtk_widget_hide (GTK_WIDGET (shell
->priv
->window
));
1489 g_signal_emit (shell
, rb_shell_signals
[VISIBILITY_CHANGED
], 0, FALSE
);
1491 g_object_unref (shell
);
1493 GDK_THREADS_LEAVE ();
1499 rb_shell_set_visibility (RBShell
*shell
,
1503 gboolean current_visible
;
1505 rb_profile_start ("changing shell visibility");
1507 current_visible
= rb_shell_get_visibility (shell
);
1508 if (!force
&& visible
== current_visible
) {
1509 rb_profile_end ("changing shell visibility");
1513 /* FIXME - see below */
1514 if (shell
->priv
->idle_hide_mainwindow_id
> 0)
1515 g_source_remove (shell
->priv
->idle_hide_mainwindow_id
);
1516 shell
->priv
->idle_hide_mainwindow_id
= 0;
1518 /* don't minimise if we have no tray icon */
1519 if (visible
|| (!force
&& !egg_tray_icon_have_manager (EGG_TRAY_ICON (shell
->priv
->tray_icon
)))) {
1520 rb_debug ("showing main window");
1521 rb_shell_sync_window_state (shell
, FALSE
);
1523 if (egg_tray_icon_have_manager (EGG_TRAY_ICON (shell
->priv
->tray_icon
)))
1524 gtk_window_set_skip_taskbar_hint (GTK_WINDOW (shell
->priv
->window
), FALSE
);
1525 gtk_widget_show (GTK_WIDGET (shell
->priv
->window
));
1526 gtk_window_deiconify (GTK_WINDOW (shell
->priv
->window
));
1528 if (GTK_WIDGET_REALIZED (GTK_WIDGET (shell
->priv
->window
)))
1529 rb_shell_present (shell
, gtk_get_current_event_time (), NULL
);
1531 gtk_widget_show_all (GTK_WIDGET (shell
->priv
->window
));
1533 g_signal_emit (shell
, rb_shell_signals
[VISIBILITY_CHANGED
], 0, visible
);
1535 eel_gconf_set_boolean (CONF_STATE_WINDOW_VISIBLE
, TRUE
);
1537 int x
, y
, width
, height
;
1539 rb_debug ("hiding main window");
1540 shell
->priv
->iconified
= TRUE
;
1541 rb_tray_icon_get_geom (shell
->priv
->tray_icon
,
1542 &x
, &y
, &width
, &height
);
1543 if (GTK_WIDGET_REALIZED (GTK_WIDGET (shell
->priv
->window
)))
1544 set_icon_geometry (GTK_WIDGET (shell
->priv
->window
)->window
,
1545 x
, y
, width
, height
);
1546 if (egg_tray_icon_have_manager (EGG_TRAY_ICON (shell
->priv
->tray_icon
)))
1547 gtk_window_set_skip_taskbar_hint (GTK_WINDOW (shell
->priv
->window
), TRUE
);
1548 gtk_window_iconify (GTK_WINDOW (shell
->priv
->window
));
1550 /* FIMXE - this is horribly evil racy workaround for a
1551 * current bug in the tasklist not noticing our hint
1554 shell
->priv
->idle_hide_mainwindow_id
=
1555 g_timeout_add (250, idle_hide_mainwindow
, g_object_ref (shell
));
1557 eel_gconf_set_boolean (CONF_STATE_WINDOW_VISIBLE
, FALSE
);
1560 rb_profile_end ("changing shell visibility");
1564 rb_shell_window_configure_cb (GtkWidget
*win
,
1565 GdkEventConfigure
*event
,
1568 if (shell
->priv
->window_small
) {
1569 rb_debug ("storing small window width of %d", event
->width
);
1570 shell
->priv
->small_width
= event
->width
;
1571 eel_gconf_set_integer (CONF_STATE_SMALL_WIDTH
, event
->width
);
1572 } else if (!shell
->priv
->window_maximised
&& !shell
->priv
->iconified
) {
1573 rb_debug ("storing window size of %d:%d", event
->width
, event
->height
);
1574 shell
->priv
->window_width
= event
->width
;
1575 shell
->priv
->window_height
= event
->height
;
1576 eel_gconf_set_integer (CONF_STATE_WINDOW_WIDTH
, event
->width
);
1577 eel_gconf_set_integer (CONF_STATE_WINDOW_HEIGHT
, event
->height
);
1580 if (shell
->priv
->window_small
|| !shell
->priv
->window_maximised
) {
1581 gtk_window_get_position (GTK_WINDOW(shell
->priv
->window
),
1582 &shell
->priv
->window_x
,
1583 &shell
->priv
->window_y
);
1585 eel_gconf_set_integer (CONF_STATE_WINDOW_X_POSITION
, shell
->priv
->window_x
);
1586 eel_gconf_set_integer (CONF_STATE_WINDOW_Y_POSITION
, shell
->priv
->window_y
);
1593 rb_shell_window_delete_cb (GtkWidget
*win
,
1597 if (shell
->priv
->party_mode
) {
1601 rb_shell_quit (shell
, NULL
);
1607 rb_shell_sync_window_state (RBShell
*shell
,
1608 gboolean dont_maximise
)
1612 rb_profile_start ("syncing window state");
1614 if (shell
->priv
->window_small
) {
1615 hints
.min_height
= -1;
1616 hints
.min_width
= -1;
1617 hints
.max_height
= -1;
1618 hints
.max_width
= 3000;
1619 gtk_window_set_default_size (GTK_WINDOW (shell
->priv
->window
),
1620 shell
->priv
->small_width
, 0);
1621 gtk_window_resize (GTK_WINDOW (shell
->priv
->window
),
1622 shell
->priv
->small_width
, 1);
1623 gtk_window_set_geometry_hints (GTK_WINDOW (shell
->priv
->window
),
1626 GDK_HINT_MIN_SIZE
| GDK_HINT_MAX_SIZE
);
1627 gtk_window_unmaximize (GTK_WINDOW (shell
->priv
->window
));
1628 rb_debug ("syncing small window width to %d", shell
->priv
->small_width
);
1630 if (!dont_maximise
) {
1631 if (shell
->priv
->window_maximised
)
1632 gtk_window_maximize (GTK_WINDOW (shell
->priv
->window
));
1634 gtk_window_unmaximize (GTK_WINDOW (shell
->priv
->window
));
1637 gtk_window_set_default_size (GTK_WINDOW (shell
->priv
->window
),
1638 shell
->priv
->window_width
,
1639 shell
->priv
->window_height
);
1640 gtk_window_resize (GTK_WINDOW (shell
->priv
->window
),
1641 shell
->priv
->window_width
,
1642 shell
->priv
->window_height
);
1643 gtk_window_set_geometry_hints (GTK_WINDOW (shell
->priv
->window
),
1649 gtk_window_move (GTK_WINDOW (shell
->priv
->window
),
1650 shell
->priv
->window_x
,
1651 shell
->priv
->window_y
);
1652 rb_profile_end ("syncing window state");
1656 source_selected_cb (RBSourceList
*sourcelist
,
1660 rb_debug ("source selected");
1661 rb_shell_select_source (shell
, source
);
1665 source_activated_cb (RBSourceList
*sourcelist
,
1669 rb_debug ("source activated");
1671 /* Stop the playing source, if any */
1672 rb_shell_player_set_playing_source (shell
->priv
->player_shell
, NULL
);
1674 /* Select the new one, and start it playing */
1675 rb_shell_select_source (shell
, source
);
1676 rb_shell_player_set_playing_source (shell
->priv
->player_shell
, source
);
1677 /* Ignore error from here */
1678 rb_shell_player_playpause (shell
->priv
->player_shell
, FALSE
, NULL
);
1682 rb_shell_db_save_error_cb (RhythmDB
*db
,
1683 const char *uri
, const GError
*error
,
1686 rb_error_dialog (GTK_WINDOW (shell
->priv
->window
),
1687 _("Error while saving song information"),
1688 "%s", error
->message
);
1692 rb_shell_db_entry_added_cb (RhythmDB
*db
,
1693 RhythmDBEntry
*entry
,
1698 if (shell
->priv
->pending_entry
== NULL
)
1701 loc
= rhythmdb_entry_get_string (entry
, RHYTHMDB_PROP_LOCATION
);
1702 rb_debug ("got entry added for %s", loc
);
1703 if (strcmp (loc
, shell
->priv
->pending_entry
) == 0) {
1704 rb_shell_play_entry (shell
, entry
);
1706 g_free (shell
->priv
->pending_entry
);
1707 shell
->priv
->pending_entry
= NULL
;
1712 rb_shell_get_source_by_entry_type (RBShell
*shell
,
1713 RhythmDBEntryType type
)
1715 return g_hash_table_lookup (shell
->priv
->sources_hash
, type
);
1719 rb_shell_register_entry_type_for_source (RBShell
*shell
,
1721 RhythmDBEntryType type
)
1723 if (shell
->priv
->sources_hash
== NULL
) {
1724 shell
->priv
->sources_hash
= g_hash_table_new (g_direct_hash
,
1727 g_assert (g_hash_table_lookup (shell
->priv
->sources_hash
, type
) == NULL
);
1728 g_hash_table_insert (shell
->priv
->sources_hash
, type
, source
);
1732 rb_shell_append_source (RBShell
*shell
,
1736 shell
->priv
->sources
1737 = g_list_append (shell
->priv
->sources
, source
);
1739 g_signal_connect_object (G_OBJECT (source
), "deleted",
1740 G_CALLBACK (rb_shell_source_deleted_cb
), shell
, 0);
1742 gtk_notebook_append_page (GTK_NOTEBOOK (shell
->priv
->notebook
),
1743 GTK_WIDGET (source
),
1744 gtk_label_new (""));
1745 gtk_widget_show (GTK_WIDGET (source
));
1747 rb_sourcelist_append (RB_SOURCELIST (shell
->priv
->sourcelist
),
1752 rb_shell_playlist_added_cb (RBPlaylistManager
*mgr
,
1756 rb_shell_append_source (shell
, source
, NULL
);
1760 rb_shell_playlist_created_cb (RBPlaylistManager
*mgr
,
1764 shell
->priv
->window_small
= FALSE
;
1765 eel_gconf_set_boolean (CONF_UI_SMALL_DISPLAY
, shell
->priv
->window_small
);
1766 eel_gconf_set_boolean (CONF_UI_SIDEPANE_HIDDEN
, shell
->priv
->window_small
);
1768 rb_shell_sync_window_state (shell
, FALSE
);
1772 rb_shell_medium_added_cb (RBRemovableMediaManager
*mgr
,
1776 rb_shell_append_source (shell
, source
, NULL
);
1780 rb_shell_transfer_progress_cb (RBRemovableMediaManager
*mgr
,
1786 rb_debug ("transferred %d tracks out of %d", done
, total
);
1792 s
= g_strdup_printf (_("Transferring track %d out of %d (%.0f%%)"),
1793 done
+ 1, total
, fraction
* 100);
1795 s
= g_strdup_printf (_("Transferring track %d out of %d"),
1798 rb_statusbar_set_progress (shell
->priv
->statusbar
,
1799 (((double)(done
) + fraction
)/total
),
1802 rb_statusbar_set_progress (shell
->priv
->statusbar
, -1, NULL
);
1807 rb_shell_source_deleted_cb (RBSource
*source
,
1810 RhythmDBEntryType entry_type
;
1812 rb_debug ("source deleted");
1814 /* remove from the map if the source owns the type */
1815 g_object_get (source
, "entry-type", &entry_type
, NULL
);
1816 if (rb_shell_get_source_by_entry_type (shell
, entry_type
) == source
) {
1817 g_hash_table_remove (shell
->priv
->sources_hash
, entry_type
);
1819 g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE
, entry_type
);
1822 if (source
== rb_shell_player_get_playing_source (shell
->priv
->player_shell
)) {
1823 rb_shell_player_set_playing_source (shell
->priv
->player_shell
, NULL
);
1825 if (source
== shell
->priv
->selected_source
) {
1826 if (source
!= RB_SOURCE (shell
->priv
->library_source
))
1827 rb_shell_select_source (shell
, RB_SOURCE (shell
->priv
->library_source
));
1829 rb_shell_select_source (shell
, NULL
);
1832 shell
->priv
->sources
= g_list_remove (shell
->priv
->sources
, source
);
1834 rb_sourcelist_remove (RB_SOURCELIST (shell
->priv
->sourcelist
), source
);
1836 gtk_notebook_remove_page (GTK_NOTEBOOK (shell
->priv
->notebook
),
1837 gtk_notebook_page_num (GTK_NOTEBOOK (shell
->priv
->notebook
),
1838 GTK_WIDGET (source
)));
1842 rb_shell_playing_source_changed_cb (RBShellPlayer
*player
,
1846 rb_debug ("playing source changed");
1847 if (source
!= RB_SOURCE (shell
->priv
->queue_source
))
1848 rb_sourcelist_set_playing_source (RB_SOURCELIST (shell
->priv
->sourcelist
),
1853 rb_shell_playing_from_queue_cb (RBShellPlayer
*player
,
1857 gboolean from_queue
;
1859 g_object_get (player
, "playing-from-queue", &from_queue
, NULL
);
1860 if (!shell
->priv
->queue_as_sidebar
) {
1861 rb_sourcelist_set_playing_source (RB_SOURCELIST (shell
->priv
->sourcelist
),
1862 rb_shell_player_get_playing_source (shell
->priv
->player_shell
));
1866 RhythmDBEntry
*entry
;
1867 RhythmDBEntryType entry_type
;
1869 /* if playing from the queue, show the playing entry as playing in the
1870 * registered source for its type, so it makes sense when 'jump to current'
1871 * jumps to it there.
1873 entry
= rb_shell_player_get_playing_entry (shell
->priv
->player_shell
);
1877 entry_type
= rhythmdb_entry_get_entry_type (entry
);
1878 source
= rb_shell_get_source_by_entry_type (shell
, entry_type
);
1879 songs
= rb_source_get_entry_view (source
);
1881 rb_entry_view_set_state (songs
, from_queue
? RB_ENTRY_VIEW_PLAYING
: RB_ENTRY_VIEW_NOT_PLAYING
);
1882 rb_sourcelist_set_playing_source (RB_SOURCELIST (shell
->priv
->sourcelist
),
1883 rb_shell_player_get_active_source (shell
->priv
->player_shell
));
1884 rhythmdb_entry_unref (entry
);
1889 rb_shell_playing_entry_changed_cb (RBShellPlayer
*player
,
1890 RhythmDBEntry
*entry
,
1893 rb_shell_notify_playing_entry (shell
, entry
, FALSE
);
1897 merge_source_ui_cb (const char *action
,
1900 gtk_ui_manager_add_ui (shell
->priv
->ui_manager
,
1901 shell
->priv
->source_ui_merge_id
,
1905 GTK_UI_MANAGER_AUTO
,
1910 rb_shell_select_source (RBShell
*shell
,
1915 if (shell
->priv
->selected_source
== source
)
1918 rb_debug ("selecting source %p", source
);
1920 if (shell
->priv
->selected_source
) {
1921 rb_source_deactivate (shell
->priv
->selected_source
);
1922 gtk_ui_manager_remove_ui (shell
->priv
->ui_manager
, shell
->priv
->source_ui_merge_id
);
1925 shell
->priv
->selected_source
= source
;
1926 rb_source_activate (shell
->priv
->selected_source
);
1929 gtk_notebook_set_current_page (GTK_NOTEBOOK (shell
->priv
->notebook
),
1930 gtk_notebook_page_num (GTK_NOTEBOOK (shell
->priv
->notebook
), GTK_WIDGET (source
)));
1932 g_signal_handlers_block_by_func (G_OBJECT (shell
->priv
->sourcelist
),
1933 G_CALLBACK (source_selected_cb
),
1935 rb_sourcelist_select (RB_SOURCELIST (shell
->priv
->sourcelist
),
1937 g_signal_handlers_unblock_by_func (G_OBJECT (shell
->priv
->sourcelist
),
1938 G_CALLBACK (source_selected_cb
),
1941 /* update services */
1942 rb_shell_clipboard_set_source (shell
->priv
->clipboard_shell
, source
);
1943 rb_shell_player_set_selected_source (shell
->priv
->player_shell
, source
);
1944 rb_source_header_set_source (shell
->priv
->source_header
, source
);
1945 rb_statusbar_set_source (shell
->priv
->statusbar
, source
);
1946 g_object_set (G_OBJECT (shell
->priv
->playlist_manager
), "source", source
, NULL
);
1947 g_object_set (G_OBJECT (shell
->priv
->removable_media_manager
), "source", source
, NULL
);
1949 /* merge the source-specific UI */
1950 actions
= rb_source_get_ui_actions (source
);
1951 g_list_foreach (actions
, (GFunc
)merge_source_ui_cb
, shell
);
1952 rb_list_deep_free (actions
);
1954 g_object_notify (G_OBJECT (shell
), "selected-source");
1958 rb_shell_player_window_title_changed_cb (RBShellPlayer
*player
,
1959 const char *window_title
,
1962 rb_shell_set_window_title (shell
, window_title
);
1966 rb_shell_player_elapsed_changed_cb (RBShellPlayer
*player
,
1970 rb_shell_set_elapsed (shell
, elapsed
);
1974 rb_shell_set_elapsed (RBShell
*shell
,
1978 char *elapsed_string
;
1981 rb_shell_player_get_playing (shell
->priv
->player_shell
, &playing
, NULL
);
1982 elapsed_string
= rb_shell_player_get_playing_time_string (shell
->priv
->player_shell
);
1984 if (shell
->priv
->cached_title
== NULL
)
1985 tooltip
= g_strdup (_("Not playing"));
1986 else if (!playing
) {
1987 /* Translators: the first %s is substituted by the song name, the second one is the elapsed and total time */
1988 tooltip
= g_strdup_printf (_("%s\nPaused, %s"),
1989 shell
->priv
->cached_title
, elapsed_string
);
1991 /* Translators: the first %s is substituted by the song name, the second one is the elapsed and total time */
1992 tooltip
= g_strdup_printf (_("%s\n%s"),
1993 shell
->priv
->cached_title
, elapsed_string
);
1996 rb_tray_icon_set_tooltip (shell
->priv
->tray_icon
, tooltip
);
1997 g_free (elapsed_string
);
2002 rb_shell_set_window_title (RBShell
*shell
,
2003 const char *window_title
)
2005 if (window_title
== NULL
) {
2006 rb_debug ("clearing title");
2008 g_free (shell
->priv
->cached_title
);
2009 shell
->priv
->cached_title
= NULL
;
2011 gtk_window_set_title (GTK_WINDOW (shell
->priv
->window
),
2018 rb_shell_player_get_playing (shell
->priv
->player_shell
, &playing
, NULL
);
2020 if (shell
->priv
->cached_title
&&
2021 !strcmp (shell
->priv
->cached_title
, window_title
) &&
2022 playing
== shell
->priv
->cached_playing
) {
2025 g_free (shell
->priv
->cached_title
);
2026 shell
->priv
->cached_title
= g_strdup (window_title
);
2027 shell
->priv
->cached_playing
= playing
;
2029 rb_debug ("setting title to \"%s\"", window_title
);
2031 /* Translators: %s is the song name */
2032 title
= g_strdup_printf (_("%s (Paused)"), window_title
);
2033 gtk_window_set_title (GTK_WINDOW (shell
->priv
->window
),
2037 gtk_window_set_title (GTK_WINDOW (shell
->priv
->window
),
2044 rb_shell_view_sidepane_changed_cb (GtkAction
*action
,
2047 eel_gconf_set_boolean (CONF_UI_SIDEPANE_HIDDEN
,
2048 !gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action
)));
2052 rb_shell_view_toolbar_changed_cb (GtkAction
*action
,
2055 eel_gconf_set_boolean (CONF_UI_TOOLBAR_HIDDEN
,
2056 !gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action
)));
2060 rb_shell_view_smalldisplay_changed_cb (GtkAction
*action
,
2065 /* don't change more than once per second, it causes weirdness */
2066 g_get_current_time (&time
);
2067 if (time
.tv_sec
== shell
->priv
->last_small_time
)
2070 shell
->priv
->last_small_time
= time
.tv_sec
;
2072 shell
->priv
->window_small
= gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action
));
2073 eel_gconf_set_boolean (CONF_UI_SMALL_DISPLAY
, shell
->priv
->window_small
);
2077 rb_shell_view_statusbar_changed_cb (GtkAction
*action
,
2080 shell
->priv
->statusbar_hidden
= !gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action
));
2081 eel_gconf_set_boolean (CONF_UI_STATUSBAR_HIDDEN
, shell
->priv
->statusbar_hidden
);
2083 rb_shell_sync_statusbar_visibility (shell
);
2087 rb_shell_view_queue_as_sidebar_changed_cb (GtkAction
*action
,
2090 shell
->priv
->queue_as_sidebar
= gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action
));
2091 eel_gconf_set_boolean (CONF_UI_QUEUE_AS_SIDEBAR
, shell
->priv
->queue_as_sidebar
);
2093 if (shell
->priv
->queue_as_sidebar
&&
2094 shell
->priv
->selected_source
== RB_SOURCE (shell
->priv
->queue_source
)) {
2095 /* queue no longer exists as a source, so change to the library */
2096 rb_shell_select_source (shell
, RB_SOURCE (shell
->priv
->library_source
));
2099 rb_shell_playing_from_queue_cb (shell
->priv
->player_shell
, NULL
, shell
);
2101 rb_shell_sync_pane_visibility (shell
);
2105 rb_shell_view_party_mode_changed_cb (GtkAction
*action
,
2108 shell
->priv
->party_mode
= gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action
));
2109 rb_shell_sync_party_mode (shell
);
2113 rb_shell_cmd_about (GtkAction
*action
,
2118 GdkPixbuf
*pixbuf
= NULL
;
2120 const char *authors
[] = {
2122 #include "MAINTAINERS.tab"
2125 #include "MAINTAINERS.old.tab"
2128 #include "AUTHORS.tab"
2132 const char *documenters
[] = {
2133 #include "DOCUMENTERS.tab"
2137 const char *translator_credits
= _("translator-credits");
2139 const char *license
[] = {
2140 N_("Rhythmbox is free software; you can redistribute it and/or modify\n"
2141 "it under the terms of the GNU General Public License as published by\n"
2142 "the Free Software Foundation; either version 2 of the License, or\n"
2143 "(at your option) any later version.\n"),
2144 N_("Rhythmbox is distributed in the hope that it will be useful,\n"
2145 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
2146 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
2147 "GNU General Public License for more details.\n"),
2148 N_("You should have received a copy of the GNU General Public License\n"
2149 "along with Rhythmbox; if not, write to the Free Software Foundation, Inc.,\n"
2150 "51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n")
2153 char *license_trans
;
2155 pixbuf
= gdk_pixbuf_new_from_file (rb_file ("about-logo.png"), NULL
);
2157 authors
[0] = _("Maintainers:");
2158 for (tem
= authors
; *tem
!= NULL
; tem
++)
2160 *tem
= _("Former Maintainers:");
2161 for (; *tem
!= NULL
; tem
++)
2163 *tem
= _("Contributors:");
2165 comment
= g_string_new (_("Music management and playback software for GNOME."));
2167 license_trans
= g_strconcat (_(license
[0]), "\n", _(license
[1]), "\n",
2168 _(license
[2]), "\n", NULL
);
2170 gtk_show_about_dialog (GTK_WINDOW (shell
->priv
->window
),
2171 "name", "Rhythmbox",
2173 "copyright", "Copyright \xc2\xa9 2005 The Rhythmbox authors\nCopyright \xc2\xa9 2003 - 2005 Colin Walters\nCopyright \xc2\xa9 2002, 2003 Jorn Baayen",
2174 "license", license_trans
,
2175 "website", "http://www.gnome.org/projects/rhythmbox",
2176 "comments", comment
->str
,
2177 "authors", (const char **) authors
,
2178 "documenters", (const char **) documenters
,
2179 "translator-credits", strcmp (translator_credits
, "translator-credits") != 0 ? translator_credits
: NULL
,
2183 g_object_unref (pixbuf
);
2184 g_string_free (comment
, TRUE
);
2185 g_free (license_trans
);
2189 rb_shell_toggle_visibility (RBShell
*shell
)
2193 visible
= rb_shell_get_visibility (shell
);
2195 rb_shell_set_visibility (shell
, !visible
, FALSE
);
2199 rb_shell_cmd_toggle_visibility (GtkAction
*action
,
2202 rb_shell_toggle_visibility (shell
);
2206 rb_shell_cmd_quit (GtkAction
*action
,
2209 rb_shell_quit (shell
, NULL
);
2213 rb_shell_cmd_contents (GtkAction
*action
,
2216 GError
*error
= NULL
;
2218 gnome_help_display ("rhythmbox.xml", NULL
, &error
);
2220 if (error
!= NULL
) {
2221 rb_error_dialog (NULL
, _("Couldn't display help"),
2222 "%s", error
->message
);
2223 g_error_free (error
);
2228 rb_shell_cmd_preferences (GtkAction
*action
,
2231 if (shell
->priv
->prefs
== NULL
) {
2232 shell
->priv
->prefs
= rb_shell_preferences_new (shell
->priv
->sources
);
2234 gtk_window_set_transient_for (GTK_WINDOW (shell
->priv
->prefs
),
2235 GTK_WINDOW (shell
->priv
->window
));
2236 gtk_widget_show_all (shell
->priv
->prefs
);
2239 gtk_window_present (GTK_WINDOW (shell
->priv
->prefs
));
2243 rb_shell_plugins_window_delete_cb (GtkWidget
*window
,
2247 gtk_widget_hide (window
);
2253 rb_shell_plugins_response_cb (GtkDialog
*dialog
,
2257 if (response_id
== GTK_RESPONSE_CLOSE
)
2258 gtk_widget_hide (GTK_WIDGET (dialog
));
2262 rb_shell_cmd_plugins (GtkAction
*action
,
2265 if (shell
->priv
->plugins
== NULL
) {
2268 shell
->priv
->plugins
= gtk_dialog_new_with_buttons (_("Configure Plugins"),
2269 GTK_WINDOW (shell
->priv
->window
),
2270 GTK_DIALOG_DESTROY_WITH_PARENT
,
2274 gtk_container_set_border_width (GTK_CONTAINER (shell
->priv
->plugins
), 5);
2275 gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (shell
->priv
->plugins
)->vbox
), 2);
2276 gtk_dialog_set_has_separator (GTK_DIALOG (shell
->priv
->plugins
), FALSE
);
2278 g_signal_connect_object (G_OBJECT (shell
->priv
->plugins
),
2280 G_CALLBACK (rb_shell_plugins_window_delete_cb
),
2282 g_signal_connect_object (G_OBJECT (shell
->priv
->plugins
),
2284 G_CALLBACK (rb_shell_plugins_response_cb
),
2287 manager
= rb_plugin_manager_new ();
2288 gtk_widget_show_all (GTK_WIDGET (manager
));
2289 gtk_container_add (GTK_CONTAINER (GTK_DIALOG (shell
->priv
->plugins
)->vbox
),
2293 gtk_window_present (GTK_WINDOW (shell
->priv
->plugins
));
2297 add_to_library_response_cb (GtkDialog
*dialog
,
2302 char *current_dir
= NULL
;
2303 GSList
*uri_list
= NULL
, *uris
= NULL
;
2305 if (response_id
!= GTK_RESPONSE_ACCEPT
) {
2306 gtk_widget_destroy (GTK_WIDGET (dialog
));
2310 current_dir
= gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dialog
));
2311 eel_gconf_set_string (CONF_STATE_ADD_DIR
, current_dir
);
2313 uri_list
= gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog
));
2314 if (uri_list
== NULL
) {
2315 uri_list
= g_slist_prepend (uri_list
, g_strdup (current_dir
));
2318 for (uris
= uri_list
; uris
; uris
= uris
->next
) {
2319 rb_shell_load_uri (shell
, (char *)uris
->data
, FALSE
, NULL
);
2320 g_free (uris
->data
);
2322 g_slist_free (uri_list
);
2323 g_free (current_dir
);
2324 gtk_widget_destroy (GTK_WIDGET (dialog
));
2326 if (shell
->priv
->save_db_id
> 0) {
2327 g_source_remove (shell
->priv
->save_db_id
);
2329 shell
->priv
->save_db_id
= g_timeout_add (10000, (GSourceFunc
) idle_save_rhythmdb
, shell
);
2333 rb_shell_cmd_add_folder_to_library (GtkAction
*action
,
2336 char * dir
= eel_gconf_get_string (CONF_STATE_ADD_DIR
);
2339 dialog
= rb_file_chooser_new (_("Import Folder into Library"),
2340 GTK_WINDOW (shell
->priv
->window
),
2341 GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER
,
2343 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog
), TRUE
);
2345 gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (dialog
),
2348 g_signal_connect_object (G_OBJECT (dialog
),
2350 G_CALLBACK (add_to_library_response_cb
),
2355 rb_shell_cmd_add_file_to_library (GtkAction
*action
,
2358 char * dir
= eel_gconf_get_string (CONF_STATE_ADD_DIR
);
2361 dialog
= rb_file_chooser_new (_("Import File into Library"),
2362 GTK_WINDOW (shell
->priv
->window
),
2363 GTK_FILE_CHOOSER_ACTION_OPEN
,
2365 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog
), TRUE
);
2367 gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (dialog
),
2370 g_signal_connect_object (G_OBJECT (dialog
),
2372 G_CALLBACK (add_to_library_response_cb
),
2377 quit_timeout (gpointer dummy
)
2379 GDK_THREADS_ENTER ();
2381 GDK_THREADS_LEAVE ();
2386 rb_shell_quit (RBShell
*shell
,
2389 rb_debug ("Quitting");
2391 /* Stop the playing source, if any */
2392 rb_shell_player_set_playing_source (shell
->priv
->player_shell
, NULL
);
2394 rb_plugins_engine_shutdown ();
2396 rb_podcast_source_shutdown (shell
->priv
->podcast_source
);
2398 rb_shell_shutdown (shell
);
2399 rb_shell_sync_state (shell
);
2400 g_object_unref (G_OBJECT (shell
));
2402 g_timeout_add (10000, quit_timeout
, NULL
);
2407 idle_handle_load_complete (RBShell
*shell
)
2409 GDK_THREADS_ENTER ();
2411 rb_debug ("load complete");
2413 rb_playlist_manager_load_playlists (shell
->priv
->playlist_manager
);
2414 shell
->priv
->load_complete
= TRUE
;
2415 shell
->priv
->save_playlist_id
= g_timeout_add (10000, (GSourceFunc
) idle_save_playlist_manager
, shell
);
2417 rhythmdb_start_action_thread (shell
->priv
->db
);
2419 GDK_THREADS_LEAVE ();
2425 rb_shell_load_complete_cb (RhythmDB
*db
,
2428 g_idle_add ((GSourceFunc
) idle_handle_load_complete
, shell
);
2432 rb_shell_sync_sidepane_visibility (RBShell
*shell
)
2437 visible
= !eel_gconf_get_boolean (CONF_UI_SIDEPANE_HIDDEN
);
2440 gtk_widget_show (GTK_WIDGET (shell
->priv
->sidebar_container
));
2442 gtk_widget_hide (GTK_WIDGET (shell
->priv
->sidebar_container
));
2445 action
= gtk_action_group_get_action (shell
->priv
->actiongroup
,
2447 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action
),
2452 rb_shell_sync_pane_visibility (RBShell
*shell
)
2456 if (shell
->priv
->queue_source
!= NULL
) {
2457 g_object_set (G_OBJECT (shell
->priv
->queue_source
), "visibility", !shell
->priv
->queue_as_sidebar
, NULL
);
2460 if (shell
->priv
->queue_as_sidebar
) {
2461 gtk_widget_show (shell
->priv
->queue_sidebar
);
2463 gtk_widget_hide (shell
->priv
->queue_sidebar
);
2466 action
= gtk_action_group_get_action (shell
->priv
->actiongroup
,
2467 "ViewQueueAsSidebar");
2468 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action
),
2469 shell
->priv
->queue_as_sidebar
);
2473 rb_shell_sync_toolbar_state (RBShell
*shell
)
2478 guint toolbar_style
;
2480 visible
= !eel_gconf_get_boolean (CONF_UI_TOOLBAR_HIDDEN
);
2482 toolbar
= gtk_ui_manager_get_widget (shell
->priv
->ui_manager
, "/ToolBar");
2484 gtk_widget_show (toolbar
);
2486 gtk_widget_hide (toolbar
);
2488 action
= gtk_action_group_get_action (shell
->priv
->actiongroup
,
2490 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action
),
2493 /* icons-only in small mode */
2494 if (shell
->priv
->window_small
)
2497 toolbar_style
= eel_gconf_get_integer (CONF_UI_TOOLBAR_STYLE
);
2499 switch (toolbar_style
) {
2502 gtk_toolbar_unset_style (GTK_TOOLBAR (toolbar
));
2505 /* text below icons */
2506 gtk_toolbar_set_style (GTK_TOOLBAR (toolbar
), GTK_TOOLBAR_BOTH
);
2509 /* text beside icons */
2510 gtk_toolbar_set_style (GTK_TOOLBAR (toolbar
), GTK_TOOLBAR_BOTH_HORIZ
);
2514 gtk_toolbar_set_style (GTK_TOOLBAR (toolbar
), GTK_TOOLBAR_ICONS
);
2518 gtk_toolbar_set_style (GTK_TOOLBAR (toolbar
), GTK_TOOLBAR_TEXT
);
2521 g_warning ("unknown toolbar style type");
2522 gtk_toolbar_unset_style (GTK_TOOLBAR (toolbar
));
2527 window_state_event_cb (GtkWidget
*widget
,
2528 GdkEventWindowState
*event
,
2531 if (event
->changed_mask
& GDK_WINDOW_STATE_ICONIFIED
) {
2532 rb_shell_present (shell
, gtk_get_current_event_time (), NULL
);
2539 rb_shell_sync_party_mode (RBShell
*shell
)
2543 /* party mode does not use gconf as a model since it
2544 should not be persistent */
2546 /* disable/enable quit action */
2547 action
= gtk_action_group_get_action (shell
->priv
->actiongroup
, "MusicClose");
2548 g_object_set (G_OBJECT (action
), "sensitive", !shell
->priv
->party_mode
, NULL
);
2549 action
= gtk_action_group_get_action (shell
->priv
->actiongroup
, "MusicQuit");
2550 g_object_set (G_OBJECT (action
), "sensitive", !shell
->priv
->party_mode
, NULL
);
2551 action
= gtk_action_group_get_action (shell
->priv
->actiongroup
, "ViewSmallDisplay");
2552 g_object_set (G_OBJECT (action
), "sensitive", !shell
->priv
->party_mode
, NULL
);
2554 /* show/hide queue as sidebar ? */
2556 g_object_set (shell
->priv
->player_shell
, "queue-only", shell
->priv
->party_mode
, NULL
);
2558 /* Set playlist manager source to the current source to update properties */
2559 if (shell
->priv
->selected_source
) {
2560 g_object_set (G_OBJECT (shell
->priv
->playlist_manager
), "source", shell
->priv
->selected_source
, NULL
);
2561 rb_shell_clipboard_set_source (shell
->priv
->clipboard_shell
, shell
->priv
->selected_source
);
2564 gtk_window_set_keep_above (GTK_WINDOW (shell
->priv
->window
), shell
->priv
->party_mode
);
2565 if (shell
->priv
->party_mode
) {
2566 gtk_window_fullscreen (GTK_WINDOW (shell
->priv
->window
));
2567 gtk_window_stick (GTK_WINDOW (shell
->priv
->window
));
2568 g_signal_connect (shell
->priv
->window
, "window-state-event", G_CALLBACK (window_state_event_cb
), shell
);
2570 gtk_window_unstick (GTK_WINDOW (shell
->priv
->window
));
2571 gtk_window_unfullscreen (GTK_WINDOW (shell
->priv
->window
));
2572 g_signal_handlers_disconnect_by_func (shell
->priv
->window
, window_state_event_cb
, shell
);
2577 rb_shell_sync_smalldisplay (RBShell
*shell
)
2580 GtkAction
*queue_action
;
2581 GtkAction
*party_mode_action
;
2584 rb_shell_sync_window_state (shell
, FALSE
);
2586 action
= gtk_action_group_get_action (shell
->priv
->actiongroup
,
2588 queue_action
= gtk_action_group_get_action (shell
->priv
->actiongroup
,
2589 "ViewQueueAsSidebar");
2590 party_mode_action
= gtk_action_group_get_action (shell
->priv
->actiongroup
,
2593 toolbar
= gtk_ui_manager_get_widget (shell
->priv
->ui_manager
, "/ToolBar");
2595 if (shell
->priv
->window_small
) {
2596 g_object_set (G_OBJECT (action
), "sensitive", FALSE
, NULL
);
2597 g_object_set (G_OBJECT (queue_action
), "sensitive", FALSE
, NULL
);
2598 g_object_set (G_OBJECT (party_mode_action
), "sensitive", FALSE
, NULL
);
2600 gtk_widget_hide (GTK_WIDGET (shell
->priv
->paned
));
2602 g_object_set (G_OBJECT (action
), "sensitive", TRUE
, NULL
);
2603 g_object_set (G_OBJECT (queue_action
), "sensitive", TRUE
, NULL
);
2604 g_object_set (G_OBJECT (party_mode_action
), "sensitive", TRUE
, NULL
);
2606 gtk_widget_show (GTK_WIDGET (shell
->priv
->paned
));
2608 rb_shell_sync_statusbar_visibility (shell
);
2609 rb_shell_sync_toolbar_state (shell
);
2611 rb_source_header_sync_control_state (shell
->priv
->source_header
);
2613 action
= gtk_action_group_get_action (shell
->priv
->actiongroup
,
2614 "ViewSmallDisplay");
2615 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action
),
2616 shell
->priv
->window_small
);
2620 rb_shell_sync_statusbar_visibility (RBShell
*shell
)
2622 if (shell
->priv
->statusbar_hidden
|| shell
->priv
->window_small
)
2623 gtk_widget_hide (GTK_WIDGET (shell
->priv
->statusbar
));
2625 gtk_widget_show (GTK_WIDGET (shell
->priv
->statusbar
));
2629 sidepane_visibility_changed_cb (GConfClient
*client
,
2634 rb_debug ("sidepane visibility changed");
2635 rb_shell_sync_sidepane_visibility (shell
);
2639 toolbar_state_changed_cb (GConfClient
*client
,
2644 rb_debug ("toolbar state changed");
2645 rb_shell_sync_toolbar_state (shell
);
2649 smalldisplay_changed_cb (GConfClient
*client
,
2654 rb_debug ("small display mode changed");
2655 shell
->priv
->window_small
= eel_gconf_get_boolean (CONF_UI_SMALL_DISPLAY
);
2656 rb_shell_sync_smalldisplay (shell
);
2660 rb_shell_sync_paned (RBShell
*shell
)
2662 gtk_paned_set_position (GTK_PANED (shell
->priv
->paned
),
2663 shell
->priv
->paned_position
);
2664 gtk_paned_set_position (GTK_PANED (shell
->priv
->queue_paned
),
2665 shell
->priv
->sourcelist_height
);
2669 paned_size_allocate_cb (GtkWidget
*widget
,
2670 GtkAllocation
*allocation
,
2673 shell
->priv
->paned_position
= gtk_paned_get_position (GTK_PANED (shell
->priv
->paned
));
2674 rb_debug ("paned position %d", shell
->priv
->paned_position
);
2675 eel_gconf_set_integer (CONF_STATE_PANED_POSITION
, shell
->priv
->paned_position
);
2679 sidebar_paned_size_allocate_cb (GtkWidget
*widget
,
2680 GtkAllocation
*allocation
,
2683 shell
->priv
->sourcelist_height
= gtk_paned_get_position (GTK_PANED (shell
->priv
->queue_paned
));
2684 rb_debug ("sidebar paned position %d", shell
->priv
->sourcelist_height
);
2685 eel_gconf_set_integer (CONF_STATE_SOURCELIST_HEIGHT
, shell
->priv
->sourcelist_height
);
2689 sourcelist_drag_received_cb (RBSourceList
*sourcelist
,
2691 GtkSelectionData
*data
,
2694 if (source
== NULL
) {
2695 source
= rb_playlist_manager_new_playlist_from_selection_data (shell
->priv
->playlist_manager
,
2699 if (source
!= NULL
) {
2700 rb_source_receive_drag (source
, data
);
2706 rb_shell_cmd_current_song (GtkAction
*action
,
2709 rb_debug ("current song");
2711 rb_shell_jump_to_current (shell
);
2715 rb_shell_cmd_view_all (GtkAction
*action
,
2718 rb_debug ("view all");
2720 rb_source_reset_filters (shell
->priv
->selected_source
);
2721 rb_source_header_clear_search (shell
->priv
->source_header
);
2722 rb_source_header_focus_search_box (shell
->priv
->source_header
);
2726 rb_shell_jump_to_entry_with_source (RBShell
*shell
,
2728 RhythmDBEntry
*entry
)
2732 g_return_if_fail (entry
!= NULL
);
2734 if ((source
== RB_SOURCE (shell
->priv
->queue_source
) &&
2735 shell
->priv
->queue_as_sidebar
) ||
2737 RhythmDBEntryType entry_type
;
2738 entry_type
= rhythmdb_entry_get_entry_type (entry
);
2739 source
= rb_shell_get_source_by_entry_type (shell
, entry_type
);
2744 songs
= rb_source_get_entry_view (source
);
2745 rb_shell_select_source (shell
, source
);
2747 rb_entry_view_scroll_to_entry (songs
, entry
);
2748 rb_entry_view_select_entry (songs
, entry
);
2752 rb_shell_play_entry (RBShell
*shell
,
2753 RhythmDBEntry
*entry
)
2755 rb_shell_player_stop (shell
->priv
->player_shell
);
2756 rb_shell_jump_to_entry_with_source (shell
, NULL
, entry
);
2757 rb_shell_player_play_entry (shell
->priv
->player_shell
, entry
, NULL
);
2761 rb_shell_jump_to_current (RBShell
*shell
)
2764 RhythmDBEntry
*playing
;
2766 source
= rb_shell_player_get_playing_source (shell
->priv
->player_shell
);
2768 g_return_if_fail (source
!= NULL
);
2770 playing
= rb_shell_player_get_playing_entry (shell
->priv
->player_shell
);
2772 rb_shell_jump_to_entry_with_source (shell
, source
, playing
);
2773 rhythmdb_entry_unref (playing
);
2777 rb_shell_show_popup_cb (RBSourceList
*sourcelist
,
2782 return rb_source_show_popup (target
);
2786 tray_embedded_cb (GtkPlug
*plug
,
2789 /* FIXME - this doens't work */
2791 RBShell
*shell
= RB_SHELL (data
);
2793 rb_debug ("got embedded signal");
2795 gdk_window_set_decorations (shell
->priv
->window
->window
,
2796 GDK_DECOR_ALL
| GDK_DECOR_MINIMIZE
| GDK_DECOR_MAXIMIZE
);
2801 tray_destroy_cb (GtkObject
*object
,
2804 if (shell
->priv
->tray_icon
) {
2805 rb_debug ("caught destroy event for tray icon %p", object
);
2806 gtk_object_sink (object
);
2807 shell
->priv
->tray_icon
= NULL
;
2808 rb_debug ("finished sinking tray");
2811 rb_debug ("creating new tray icon");
2812 shell
->priv
->tray_icon
= rb_tray_icon_new (shell
->priv
->ui_manager
, shell
);
2813 g_signal_connect_object (G_OBJECT (shell
->priv
->tray_icon
), "destroy",
2814 G_CALLBACK (tray_destroy_cb
), shell
, 0);
2815 g_signal_connect_object (G_OBJECT (shell
->priv
->tray_icon
), "embedded",
2816 G_CALLBACK (tray_embedded_cb
), shell
, 0);
2818 gtk_widget_show_all (GTK_WIDGET (shell
->priv
->tray_icon
));
2820 rb_debug ("done creating new tray icon %p", shell
->priv
->tray_icon
);
2826 rb_shell_notify_playing_entry (RBShell
*shell
,
2827 RhythmDBEntry
*entry
,
2831 char *stream_title
= NULL
;
2832 char *artist
= NULL
;
2841 secondary
= g_string_sized_new (100);
2843 /* get artist, preferring streaming song details */
2844 value
= rhythmdb_entry_request_extra_metadata (shell
->priv
->db
,
2846 RHYTHMDB_PROP_STREAM_SONG_ARTIST
);
2847 if (value
!= NULL
) {
2848 artist
= g_value_dup_string (value
);
2849 g_value_unset (value
);
2852 artist
= rhythmdb_entry_dup_string (entry
, RHYTHMDB_PROP_ARTIST
);
2855 if (artist
!= NULL
&& artist
[0] != '\0') {
2856 /* Translators: by Artist */
2857 g_string_append_printf (secondary
, _("by %s"), artist
);
2861 /* get album, preferring streaming song details */
2862 value
= rhythmdb_entry_request_extra_metadata (shell
->priv
->db
,
2864 RHYTHMDB_PROP_STREAM_SONG_ALBUM
);
2865 if (value
!= NULL
) {
2866 album
= g_value_dup_string (value
);
2867 g_value_unset (value
);
2870 album
= rhythmdb_entry_dup_string (entry
, RHYTHMDB_PROP_ALBUM
);
2873 if (album
!= NULL
&& album
[0] != '\0') {
2874 if (secondary
->len
!= 0)
2875 g_string_append_c (secondary
, ' ');
2877 /* Translators: from Album */
2878 g_string_append_printf (secondary
, _("from %s"), album
);
2882 /* get title and possibly stream name.
2883 * if we have a streaming song title, the entry's title
2884 * property is the stream name.
2886 value
= rhythmdb_entry_request_extra_metadata (shell
->priv
->db
,
2888 RHYTHMDB_PROP_STREAM_SONG_TITLE
);
2889 if (value
!= NULL
) {
2890 title
= g_value_dup_string (value
);
2891 g_value_unset (value
);
2894 stream_title
= rhythmdb_entry_dup_string (entry
, RHYTHMDB_PROP_TITLE
);
2896 title
= rhythmdb_entry_dup_string (entry
, RHYTHMDB_PROP_TITLE
);
2899 if (stream_title
!= NULL
&& stream_title
[0] != '\0') {
2900 if (secondary
->len
== 0)
2901 g_string_append (secondary
, stream_title
);
2903 g_string_append_printf (secondary
, " (%s)", stream_title
);
2905 g_free (stream_title
);
2907 sec
= g_string_free (secondary
, FALSE
);
2908 rb_shell_hidden_notify (shell
,
2919 rb_shell_hidden_notify (RBShell
*shell
,
2921 const char *primary
,
2923 const char *secondary
,
2927 if (requested
== FALSE
&& rb_shell_get_visibility (shell
)) {
2928 rb_debug ("shell is visible, not notifying");
2932 rb_tray_icon_notify (shell
->priv
->tray_icon
,
2941 rb_shell_do_notify (RBShell
*shell
, gboolean requested
, GError
**error
)
2943 RhythmDBEntry
*entry
;
2945 entry
= rb_shell_player_get_playing_entry (shell
->priv
->player_shell
);
2946 rb_shell_notify_playing_entry (shell
, entry
, requested
);
2947 rhythmdb_entry_unref (entry
);
2953 session_die_cb (GnomeClient
*client
,
2956 rb_debug ("session die");
2957 rb_shell_quit (shell
, NULL
);
2961 rb_shell_error_quark (void)
2963 static GQuark quark
= 0;
2965 quark
= g_quark_from_static_string ("rb_shell_error");
2971 save_yourself_cb (GnomeClient
*client
,
2973 GnomeSaveStyle save_style
,
2975 GnomeInteractStyle interact_style
,
2979 rb_debug ("session save yourself");
2980 rb_shell_sync_state (shell
);
2985 rb_shell_session_init (RBShell
*shell
)
2987 GnomeClient
*client
;
2989 client
= gnome_master_client ();
2991 g_signal_connect_object (G_OBJECT (client
),
2993 G_CALLBACK (save_yourself_cb
),
2996 g_signal_connect_object (G_OBJECT (client
),
2998 G_CALLBACK (session_die_cb
),
3003 rb_shell_guess_source_for_uri (RBShell
*shell
,
3007 RBSource
*best
= NULL
;
3010 for (t
= shell
->priv
->sources
; t
!= NULL
; t
= t
->next
) {
3014 source
= (RBSource
*)t
->data
;
3015 s
= rb_source_want_uri (source
, uri
);
3019 g_object_get (source
, "name", &name
, NULL
);
3020 rb_debug ("source %s returned strength %u for uri %s",
3032 /* Load a URI representing an element of the given type, with
3036 rb_shell_add_uri (RBShell
*shell
,
3044 source
= rb_shell_guess_source_for_uri (shell
, uri
);
3045 if (source
== NULL
) {
3048 RB_SHELL_ERROR_NO_SOURCE_FOR_URI
,
3049 _("No registered source can handle URI %s"),
3054 rb_source_add_uri (source
, uri
, title
, genre
);
3060 gboolean can_use_playlist
;
3061 RBSource
*playlist_source
;
3062 } PlaylistParseData
;
3065 handle_playlist_entry_cb (TotemPlParser
*playlist
,
3069 PlaylistParseData
*data
)
3074 * Track whether the same playlist-handling source
3075 * wants all the URIs from the playlist; if it does,
3076 * then we'll just give the playlist URI to the source.
3078 if (data
->can_use_playlist
== FALSE
)
3081 source
= rb_shell_guess_source_for_uri (data
->shell
, uri
);
3082 if (data
->playlist_source
== NULL
) {
3083 if (source
!= NULL
&& rb_source_try_playlist (source
)) {
3084 data
->playlist_source
= RB_SOURCE (g_object_ref (source
));
3086 data
->can_use_playlist
= FALSE
;
3088 } else if (data
->playlist_source
!= source
) {
3089 g_object_unref (data
->playlist_source
);
3090 data
->playlist_source
= NULL
;
3091 data
->can_use_playlist
= FALSE
;
3095 /* Load a URI representing a single song, a directory, a playlist, or
3096 * an internet radio station, and optionally start playing it.
3098 * For playlists containing only stream URLs, we either add the playlist
3099 * itself (if it's remote) or each URL from it (if it's local). The main
3100 * reason for this is so clicking on stream playlist links in web browsers
3101 * works properly - the playlist file will be downloaded to /tmp/, and
3102 * we can't add that to the database, so we need to add the stream URLs
3106 rb_shell_load_uri (RBShell
*shell
,
3111 RhythmDBEntry
*entry
;
3112 entry
= rhythmdb_entry_lookup_by_location (shell
->priv
->db
, uri
);
3114 if (entry
== NULL
) {
3115 TotemPlParser
*parser
;
3116 TotemPlParserResult result
;
3117 PlaylistParseData data
;
3120 data
.can_use_playlist
= TRUE
;
3121 data
.playlist_source
= NULL
;
3123 rb_debug ("adding uri %s", uri
);
3124 parser
= totem_pl_parser_new ();
3126 g_signal_connect_data (G_OBJECT (parser
), "entry",
3127 G_CALLBACK (handle_playlist_entry_cb
),
3130 totem_pl_parser_add_ignored_mimetype (parser
, "x-directory/normal");
3131 if (g_object_class_find_property (G_OBJECT_GET_CLASS (parser
), "recurse"))
3132 g_object_set (G_OBJECT (parser
), "recurse", FALSE
, NULL
);
3134 result
= totem_pl_parser_parse (parser
, uri
, FALSE
);
3135 g_object_unref (parser
);
3137 if (result
== TOTEM_PL_PARSER_RESULT_SUCCESS
) {
3138 if (data
.can_use_playlist
&& data
.playlist_source
) {
3139 rb_debug ("adding playlist %s to source", uri
);
3140 rb_source_add_uri (data
.playlist_source
, uri
, NULL
, NULL
);
3141 g_object_unref (data
.playlist_source
);
3143 /* FIXME: We need some way to determine whether the URI as
3144 * given will appear in the db, or whether something else will.
3145 * This hack assumes we'll never add local playlists to the db
3148 if (rb_uri_is_local (uri
)) {
3152 rb_debug ("adding %s as a static playlist", uri
);
3153 if (!rb_playlist_manager_parse_file (shell
->priv
->playlist_manager
,
3158 rb_debug ("%s didn't parse as a playlist", uri
);
3159 if (!rb_shell_add_uri (shell
, uri
, NULL
, NULL
, error
))
3166 entry
= rhythmdb_entry_lookup_by_location (shell
->priv
->db
, uri
);
3169 rb_shell_play_entry (shell
, entry
);
3171 /* wait for the entry to be added, and then play it */
3172 if (shell
->priv
->pending_entry
)
3173 g_free (shell
->priv
->pending_entry
);
3175 shell
->priv
->pending_entry
= g_strdup (uri
);
3183 rb_shell_get_party_mode (RBShell
*shell
)
3185 return shell
->priv
->party_mode
;
3189 rb_shell_get_player (RBShell
*shell
)
3191 return G_OBJECT (shell
->priv
->player_shell
);
3195 rb_shell_get_player_path (RBShell
*shell
)
3197 return "/org/gnome/Rhythmbox/Player";
3201 rb_shell_get_playlist_manager (RBShell
*shell
)
3203 return G_OBJECT (shell
->priv
->playlist_manager
);
3207 rb_shell_get_playlist_manager_path (RBShell
*shell
)
3209 return "/org/gnome/Rhythmbox/PlaylistManager";
3213 rb_shell_get_ui_manager (RBShell
*shell
)
3215 return G_OBJECT (shell
->priv
->ui_manager
);
3219 rb_shell_add_to_queue (RBShell
*shell
,
3223 rb_static_playlist_source_add_location (RB_STATIC_PLAYLIST_SOURCE (shell
->priv
->queue_source
),
3229 rb_shell_remove_from_queue (RBShell
*shell
,
3233 if (rb_playlist_source_location_in_map (RB_PLAYLIST_SOURCE (shell
->priv
->queue_source
), uri
))
3234 rb_static_playlist_source_remove_location (RB_STATIC_PLAYLIST_SOURCE (shell
->priv
->queue_source
),
3240 rb_shell_clear_queue (RBShell
*shell
,
3243 rb_play_queue_source_clear_queue (RB_PLAY_QUEUE_SOURCE (shell
->priv
->queue_source
));
3248 rb_shell_present (RBShell
*shell
,
3252 rb_profile_start ("presenting shell");
3254 rb_debug ("presenting with timestamp %u", timestamp
);
3255 gtk_widget_show (GTK_WIDGET (shell
->priv
->window
));
3256 #if GTK_MINOR_VERSION >= 8
3257 gtk_window_present_with_time (GTK_WINDOW (shell
->priv
->window
), timestamp
);
3259 gtk_window_present (GTK_WINDOW (shell
->priv
->window
));
3260 gdk_window_focus (GTK_WIDGET (shell
->priv
->window
)->window
, timestamp
);
3262 gtk_window_set_skip_taskbar_hint (GTK_WINDOW (shell
->priv
->window
), FALSE
);
3264 rb_profile_end ("presenting shell");
3270 rb_shell_get_song_properties (RBShell
*shell
,
3272 GHashTable
**properties
,
3275 RhythmDBEntry
*entry
;
3277 entry
= rhythmdb_entry_lookup_by_location (shell
->priv
->db
, uri
);
3279 if (entry
== NULL
) {
3282 RB_SHELL_ERROR_NO_SUCH_URI
,
3283 _("Unknown song URI: %s"),
3288 *properties
= rhythmdb_entry_gather_metadata (shell
->priv
->db
, entry
);
3289 return (*properties
!= NULL
);
3293 rb_shell_set_song_property (RBShell
*shell
,
3295 const char *propname
,
3296 const GValue
*value
,
3299 RhythmDBEntry
*entry
;
3303 entry
= rhythmdb_entry_lookup_by_location (shell
->priv
->db
, uri
);
3305 if (entry
== NULL
) {
3308 RB_SHELL_ERROR_NO_SUCH_URI
,
3309 _("Unknown song URI: %s"),
3314 if ((propid
= rhythmdb_propid_from_nice_elt_name (shell
->priv
->db
, (guchar
*) propname
)) < 0) {
3317 RB_SHELL_ERROR_NO_SUCH_PROPERTY
,
3318 _("Unknown property %s"),
3323 proptype
= rhythmdb_get_property_type (shell
->priv
->db
, propid
);
3324 if (G_VALUE_TYPE (value
) != proptype
) {
3327 RB_SHELL_ERROR_INVALID_PROPERTY_TYPE
,
3328 _("Invalid property type %s for property %s"),
3329 g_type_name (G_VALUE_TYPE (value
)),
3334 rhythmdb_entry_set (shell
->priv
->db
, entry
, propid
, value
);
3339 rb_shell_volume_widget_changed_cb (BaconVolumeButton
*vol
,
3342 if (!shell
->priv
->syncing_volume
)
3343 g_object_set (shell
->priv
->player_shell
,
3344 "volume", bacon_volume_button_get_value (vol
),
3349 rb_shell_player_volume_changed_cb (RBShellPlayer
*player
,
3355 g_object_get (player
, "volume", &volume
, NULL
);
3356 shell
->priv
->syncing_volume
= TRUE
;
3357 bacon_volume_button_set_value (BACON_VOLUME_BUTTON (shell
->priv
->volume_button
),
3359 shell
->priv
->syncing_volume
= FALSE
;
3364 rb_shell_druid_response_cb (GtkDialog
*druid
,
3368 gtk_widget_show_all (GTK_WIDGET (shell
->priv
->window
));
3369 gtk_widget_destroy (GTK_WIDGET (druid
));
3373 rb_shell_get_box_for_ui_location (RBShell
*shell
, RBShellUILocation location
)
3378 case RB_SHELL_UI_LOCATION_SIDEBAR
:
3379 box
= shell
->priv
->sidebar_container
;
3381 case RB_SHELL_UI_LOCATION_MAIN_TOP
:
3382 box
= shell
->priv
->top_container
;
3384 case RB_SHELL_UI_LOCATION_MAIN_BOTTOM
:
3385 box
= shell
->priv
->bottom_container
;
3393 rb_shell_add_widget (RBShell
*shell
, GtkWidget
*widget
, RBShellUILocation location
)
3397 box
= rb_shell_get_box_for_ui_location (shell
, location
);
3398 g_return_if_fail (box
!= NULL
);
3400 gtk_box_pack_start (box
, widget
, FALSE
, TRUE
, 0);
3404 rb_shell_remove_widget (RBShell
*shell
, GtkWidget
*widget
, RBShellUILocation location
)
3408 box
= rb_shell_get_box_for_ui_location (shell
, location
);
3409 g_return_if_fail (box
!= NULL
);
3411 gtk_container_remove (GTK_CONTAINER (box
), widget
);
3414 /* This should really be standard. */
3415 #define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
3418 rb_shell_ui_location_get_type (void)
3420 static GType etype
= 0;
3423 static const GEnumValue values
[] = {
3424 ENUM_ENTRY (RB_SHELL_UI_LOCATION_SIDEBAR
, "Sidebar"),
3425 ENUM_ENTRY (RB_SHELL_UI_LOCATION_MAIN_TOP
, "Main Top"),
3426 ENUM_ENTRY (RB_SHELL_UI_LOCATION_MAIN_BOTTOM
, "Main Bottom"),
3430 etype
= g_enum_register_static ("RBShellUILocation", values
);