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 <libgnomeui/gnome-stock-icons.h>
40 #include <libgnome/gnome-init.h>
41 #include <libgnome/gnome-program.h>
42 #include <libgnomeui/gnome-window-icon.h>
43 #include <libgnomeui/gnome-client.h>
45 #include <libgnomevfs/gnome-vfs.h>
46 #include <libgnomevfs/gnome-vfs-mime-utils.h>
50 #include "rb-dialog.h"
51 #ifdef WITH_RHYTHMDB_TREE
52 #include "rhythmdb-tree.h"
53 #elif defined(WITH_RHYTHMDB_GDA)
54 #include "rhythmdb-gda.h"
56 #error "no database specified. configure broken?"
58 #include "rb-stock-icons.h"
59 #include "rb-sourcelist.h"
60 #include "rb-file-helpers.h"
61 #include "rb-source.h"
62 #include "rb-playlist-manager.h"
63 #include "rb-removable-media-manager.h"
64 #include "rb-preferences.h"
66 #include "rb-shell-clipboard.h"
67 #include "rb-shell-player.h"
68 #include "rb-source-header.h"
69 #include "rb-tray-icon.h"
70 #include "rb-statusbar.h"
71 #include "rb-shell-preferences.h"
72 #include "rb-library-source.h"
73 #include "rb-podcast-source.h"
74 #include "totem-pl-parser.h"
75 #ifdef WITH_DAAP_SUPPORT
76 #include "rb-daap-source.h"
77 #include "rb-daap-sharing.h"
78 #endif /* WITH_DAAP_SUPPORT */
79 #include "rb-iradio-source.h"
80 #include "rb-shell-preferences.h"
81 #include "rb-playlist-source.h"
82 #include "rb-static-playlist-source.h"
83 #include "rb-play-queue-source.h"
84 #include "eel-gconf-extensions.h"
85 #include "bacon-volume.h"
86 #include "rb-missing-files-source.h"
87 #include "rb-import-errors-source.h"
88 #include "rb-plugins-engine.h"
89 #include "rb-plugin-manager.h"
90 #include "rb-proxy-config.h"
92 #include "rb-sourcelist-model.h"
94 static void rb_shell_class_init (RBShellClass
*klass
);
95 static void rb_shell_init (RBShell
*shell
);
96 static GObject
*rb_shell_constructor (GType type
,
97 guint n_construct_properties
,
98 GObjectConstructParam
*construct_properties
);
99 static void rb_shell_finalize (GObject
*object
);
100 static void rb_shell_set_property (GObject
*object
,
104 static void rb_shell_get_property (GObject
*object
,
108 static gboolean
rb_shell_get_visibility (RBShell
*shell
);
109 static gboolean
rb_shell_window_state_cb (GtkWidget
*widget
,
110 GdkEventWindowState
*event
,
112 static gboolean
rb_shell_window_configure_cb (GtkWidget
*win
,
113 GdkEventConfigure
*event
,
115 static gboolean
rb_shell_window_delete_cb (GtkWidget
*win
,
118 static void rb_shell_sync_window_state (RBShell
*shell
, gboolean dont_maximise
);
119 static void rb_shell_sync_paned (RBShell
*shell
);
120 static void rb_shell_sync_party_mode (RBShell
*shell
);
121 static void rb_shell_select_source (RBShell
*shell
, RBSource
*source
);
122 static void source_selected_cb (RBSourceList
*sourcelist
,
125 static void rb_shell_playing_source_changed_cb (RBShellPlayer
*player
,
128 static void rb_shell_playing_entry_changed_cb (RBShellPlayer
*player
,
129 RhythmDBEntry
*entry
,
131 static void rb_shell_playing_from_queue_cb (RBShellPlayer
*player
,
134 static void source_activated_cb (RBSourceList
*sourcelist
,
137 static void rb_shell_db_save_error_cb (RhythmDB
*db
,
138 const char *uri
, const GError
*error
,
140 static void rb_shell_db_entry_added_cb (RhythmDB
*db
,
141 RhythmDBEntry
*entry
,
143 static void rb_shell_druid_response_cb (GtkDialog
*druid
,
147 static void rb_shell_playlist_added_cb (RBPlaylistManager
*mgr
, RBSource
*source
, RBShell
*shell
);
148 static void rb_shell_playlist_created_cb (RBPlaylistManager
*mgr
, RBSource
*source
, RBShell
*shell
);
149 static void rb_shell_medium_added_cb (RBRemovableMediaManager
*mgr
, RBSource
*source
, RBShell
*shell
);
150 static void rb_shell_transfer_progress_cb (RBRemovableMediaManager
*mgr
,
155 static void rb_shell_source_deleted_cb (RBSource
*source
, RBShell
*shell
);
156 static void rb_shell_set_window_title (RBShell
*shell
, const char *window_title
);
157 static void rb_shell_set_elapsed (RBShell
*shell
, guint elapsed
);
158 static void rb_shell_player_window_title_changed_cb (RBShellPlayer
*player
,
159 const char *window_title
,
161 static void rb_shell_player_elapsed_changed_cb (RBShellPlayer
*player
,
164 static void rb_shell_player_stream_song_changed_cb (RBShellPlayer
*player
,
167 static void rb_shell_cmd_about (GtkAction
*action
,
169 static void rb_shell_cmd_contents (GtkAction
*action
,
171 static void rb_shell_cmd_toggle_visibility (GtkAction
*action
,
173 static void rb_shell_cmd_quit (GtkAction
*action
,
175 static void rb_shell_cmd_preferences (GtkAction
*action
,
177 static void rb_shell_cmd_plugins (GtkAction
*action
,
179 static void rb_shell_cmd_add_folder_to_library (GtkAction
*action
,
181 static void rb_shell_cmd_add_file_to_library (GtkAction
*action
,
184 static void rb_shell_cmd_extract_cd (GtkAction
*action
,
186 static void rb_shell_cmd_current_song (GtkAction
*action
,
188 static void rb_shell_jump_to_current (RBShell
*shell
);
189 static void rb_shell_jump_to_entry_with_source (RBShell
*shell
, RBSource
*source
,
190 RhythmDBEntry
*entry
);
191 static void rb_shell_play_entry (RBShell
*shell
, RhythmDBEntry
*entry
);
192 static void rb_shell_quit (RBShell
*shell
);
193 static void rb_shell_cmd_view_all (GtkAction
*action
,
195 static void rb_shell_view_sourcelist_changed_cb (GtkAction
*action
,
197 static void rb_shell_view_toolbar_changed_cb (GtkAction
*action
,
199 static void rb_shell_view_party_mode_changed_cb (GtkAction
*action
,
201 static void rb_shell_view_smalldisplay_changed_cb (GtkAction
*action
,
203 static void rb_shell_view_statusbar_changed_cb (GtkAction
*action
,
205 static void rb_shell_view_queue_as_sidebar_changed_cb (GtkAction
*action
,
207 static void rb_shell_load_complete_cb (RhythmDB
*db
, RBShell
*shell
);
208 static void rb_shell_sync_sourcelist_visibility (RBShell
*shell
);
209 static void rb_shell_sync_toolbar_state (RBShell
*shell
);
210 static void rb_shell_sync_smalldisplay (RBShell
*shell
);
211 static void rb_shell_sync_pane_visibility (RBShell
*shell
);
212 static void rb_shell_sync_statusbar_visibility (RBShell
*shell
);
213 static void rb_shell_set_visibility (RBShell
*shell
,
216 static void sourcelist_visibility_changed_cb (GConfClient
*client
,
220 static void toolbar_state_changed_cb (GConfClient
*client
,
224 static void smalldisplay_changed_cb (GConfClient
*client
,
228 static void sourcelist_drag_received_cb (RBSourceList
*sourcelist
,
230 GtkSelectionData
*data
,
232 static gboolean
rb_shell_show_popup_cb (RBSourceList
*sourcelist
,
235 static gboolean
tray_destroy_cb (GtkObject
*object
, RBShell
*shell
);
237 static gboolean
save_yourself_cb (GnomeClient
*client
,
239 GnomeSaveStyle save_style
,
241 GnomeInteractStyle interact_style
,
244 static void paned_size_allocate_cb (GtkWidget
*widget
,
245 GtkAllocation
*allocation
,
247 static void sidebar_paned_size_allocate_cb (GtkWidget
*widget
,
248 GtkAllocation
*allocation
,
250 static void rb_shell_volume_widget_changed_cb (BaconVolumeButton
*vol
,
252 static void rb_shell_player_volume_changed_cb (RBShellPlayer
*player
,
256 static void session_die_cb (GnomeClient
*client
, RBShell
*shell
);
257 static void rb_shell_session_init (RBShell
*shell
);
264 PROP_NO_REGISTRATION
,
268 PROP_SELECTED_SOURCE
,
272 PROP_PLAYLIST_MANAGER
,
273 PROP_REMOVABLE_MEDIA_MANAGER
,
280 PROP_SOURCELIST_MODEL
,
285 #define CONF_STATE_WINDOW_WIDTH CONF_PREFIX "/state/window_width"
286 #define CONF_STATE_WINDOW_HEIGHT CONF_PREFIX "/state/window_height"
287 #define CONF_STATE_SMALL_WIDTH CONF_PREFIX "/state/small_width"
288 #define CONF_STATE_WINDOW_MAXIMIZED CONF_PREFIX "/state/window_maximized"
289 #define CONF_STATE_PANED_POSITION CONF_PREFIX "/state/paned_position"
290 #define CONF_STATE_ADD_DIR CONF_PREFIX "/state/add_dir"
291 #define CONF_STATE_WINDOW_X_POSITION CONF_PREFIX "/state/window_x_position"
292 #define CONF_STATE_WINDOW_Y_POSITION CONF_PREFIX "/state/window_y_position"
293 #define CONF_STATE_SOURCELIST_HEIGHT CONF_PREFIX "/state/sourcelist_height"
301 static guint rb_shell_signals
[LAST_SIGNAL
] = { 0 };
303 G_DEFINE_TYPE (RBShell
, rb_shell
, G_TYPE_OBJECT
)
306 struct RBShellPrivate
310 guint idle_hide_mainwindow_id
;
312 GtkUIManager
*ui_manager
;
313 GtkActionGroup
*actiongroup
;
314 guint source_ui_merge_id
;
316 GtkWidget
*main_vbox
;
318 GtkWidget
*sourcelist
;
320 GtkWidget
*queue_paned
;
321 GtkWidget
*queue_sidebar
;
323 GtkBox
*sidebar_container
;
324 GtkBox
*top_container
;
325 GtkBox
*bottom_container
;
328 GHashTable
*sources_hash
;
330 guint async_state_save_id
;
331 guint save_playlist_id
;
334 gboolean shutting_down
;
335 gboolean load_complete
;
339 gboolean no_registration
;
347 RBShellPlayer
*player_shell
;
348 RBShellClipboard
*clipboard_shell
;
349 RBSourceHeader
*source_header
;
350 RBStatusbar
*statusbar
;
351 RBPlaylistManager
*playlist_manager
;
352 RBRemovableMediaManager
*removable_media_manager
;
354 GList
*supported_media_extensions
;
356 RBLibrarySource
*library_source
;
357 RBIRadioSource
*iradio_source
;
358 RBPodcastSource
*podcast_source
;
359 RBPlaylistSource
*queue_source
;
360 RBSource
*missing_files_source
;
361 RBSource
*import_errors_source
;
363 RBProxyConfig
*proxy_config
;
365 RBSource
*selected_source
;
370 RBTrayIcon
*tray_icon
;
371 GtkTooltips
*tooltips
;
372 GtkWidget
*volume_button
;
373 gboolean syncing_volume
;
376 char *cached_duration
;
377 gboolean cached_playing
;
379 guint sourcelist_visibility_notify_id
;
380 guint toolbar_visibility_notify_id
;
381 guint toolbar_style_notify_id
;
382 guint smalldisplay_notify_id
;
384 glong last_small_time
; /* when we last changed small mode */
386 /* Cached copies of the gconf keys.
388 * To avoid race conditions, the only time the keys are actually read is at startup
393 gboolean window_maximised
;
394 gboolean window_small
;
395 gboolean queue_as_sidebar
;
396 gboolean statusbar_hidden
;
401 gint sourcelist_height
;
404 #define RB_SHELL_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), RB_TYPE_SHELL, RBShellPrivate))
406 static GtkActionEntry rb_shell_actions
[] =
408 { "Music", NULL
, N_("_Music") },
409 { "Edit", NULL
, N_("_Edit") },
410 { "View", NULL
, N_("_View") },
411 { "Control", NULL
, N_("_Control") },
412 { "Tools", NULL
, N_("_Tools") },
413 { "Help", NULL
, N_("_Help") },
415 { "MusicImportFolder", GTK_STOCK_DIRECTORY
, N_("_Import Folder..."), "<control>O",
416 N_("Choose folder to be added to the Library"),
417 G_CALLBACK (rb_shell_cmd_add_folder_to_library
) },
418 { "MusicImportFile", GTK_STOCK_FILE
, N_("Import _File..."), NULL
,
419 N_("Choose file to be added to the Library"),
420 G_CALLBACK (rb_shell_cmd_add_file_to_library
) },
421 { "MusicImportCD", GTK_STOCK_CDROM
, N_("Import _Audio CD..."), "<control>E",
422 N_("Extract and import songs from a CD"),
423 G_CALLBACK (rb_shell_cmd_extract_cd
) },
424 { "HelpAbout", GTK_STOCK_ABOUT
, N_("_About"), NULL
,
425 N_("Show information about the music player"),
426 G_CALLBACK (rb_shell_cmd_about
) },
427 { "HelpContents", GTK_STOCK_HELP
, N_("_Contents"), "F1",
428 N_("Display music player help"),
429 G_CALLBACK (rb_shell_cmd_contents
) },
430 { "MusicClose", GTK_STOCK_CLOSE
, N_("_Close"), "<control>W",
431 N_("Hide the music player window"),
432 G_CALLBACK (rb_shell_cmd_toggle_visibility
) },
433 { "MusicQuit", GTK_STOCK_QUIT
, N_("_Quit"), "<control>Q",
434 N_("Quit the music player"),
435 G_CALLBACK (rb_shell_cmd_quit
) },
436 { "EditPreferences", GTK_STOCK_PREFERENCES
, N_("Prefere_nces..."), NULL
,
437 N_("Edit music player preferences"),
438 G_CALLBACK (rb_shell_cmd_preferences
) },
439 { "EditPlugins", NULL
, N_("P_lugins..."), NULL
,
440 N_("Change and configure plugins"),
441 G_CALLBACK (rb_shell_cmd_plugins
) },
442 { "ViewAll", NULL
, N_("Show _All"), "<control>Y",
443 N_("Show all items in this music source"),
444 G_CALLBACK (rb_shell_cmd_view_all
) },
445 { "ViewJumpToPlaying", GTK_STOCK_JUMP_TO
, N_("_Jump to Playing Song"), "<control>J",
446 N_("Scroll the view to the currently playing song"),
447 G_CALLBACK (rb_shell_cmd_current_song
) },
449 static guint rb_shell_n_actions
= G_N_ELEMENTS (rb_shell_actions
);
451 static GtkToggleActionEntry rb_shell_toggle_entries
[] =
453 { "ViewSourceList", NULL
, N_("Source _List"), "<control>L",
454 N_("Change the visibility of the source list"),
455 G_CALLBACK (rb_shell_view_sourcelist_changed_cb
), TRUE
},
456 { "ViewToolbar", NULL
, N_("_Toolbar"), NULL
,
457 N_("Change the visibility of the toolbar"),
458 G_CALLBACK (rb_shell_view_toolbar_changed_cb
), TRUE
},
459 { "ViewSmallDisplay", NULL
, N_("_Small Display"), "<control>D",
460 N_("Make the main window smaller"),
461 G_CALLBACK (rb_shell_view_smalldisplay_changed_cb
), },
462 { "ViewPartyMode", NULL
, N_("_Party Mode"), NULL
,
463 N_("Change the status of the party mode"),
464 G_CALLBACK (rb_shell_view_party_mode_changed_cb
), FALSE
},
465 { "ViewQueueAsSidebar", NULL
, N_("Play _Queue as Side Pane"), "<control>K",
466 N_("Change whether the queue is visible as a source or a sidebar"),
467 G_CALLBACK (rb_shell_view_queue_as_sidebar_changed_cb
) },
468 { "ViewStatusbar", NULL
, N_("S_tatusbar"), NULL
,
469 N_("Change the visibility of the statusbar"),
470 G_CALLBACK (rb_shell_view_statusbar_changed_cb
), TRUE
}
472 static guint rb_shell_n_toggle_entries
= G_N_ELEMENTS (rb_shell_toggle_entries
);
475 rb_shell_class_init (RBShellClass
*klass
)
477 GObjectClass
*object_class
= (GObjectClass
*) klass
;
479 object_class
->set_property
= rb_shell_set_property
;
480 object_class
->get_property
= rb_shell_get_property
;
481 object_class
->finalize
= rb_shell_finalize
;
482 object_class
->constructor
= rb_shell_constructor
;
484 g_object_class_install_property (object_class
,
486 g_param_spec_int ("argc",
490 0, G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
));
492 g_object_class_install_property (object_class
,
494 g_param_spec_pointer ("argv",
497 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
));
499 g_object_class_install_property (object_class
,
500 PROP_NO_REGISTRATION
,
501 g_param_spec_boolean ("no-registration",
503 "Whether or not to register",
505 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
));
507 g_object_class_install_property (object_class
,
509 g_param_spec_boolean ("no-update",
511 "Whether or not to update the library",
513 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
));
515 g_object_class_install_property (object_class
,
517 g_param_spec_boolean ("dry-run",
519 "Whether or not this is a dry run",
521 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
));
523 g_object_class_install_property (object_class
,
525 g_param_spec_string ("rhythmdb-file",
527 "The RhythmDB file to use",
528 #ifdef WITH_RHYTHMDB_TREE
530 #elif defined(WITH_RHYTHMDB_GDA)
531 "rhythmdb.sqlite", /* FIXME: correct extension? */
533 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
));
535 g_object_class_install_property (object_class
,
536 PROP_SELECTED_SOURCE
,
537 g_param_spec_object ("selected-source",
539 "Source which is currently selected",
544 g_object_class_install_property (object_class
,
546 g_param_spec_object ("db",
552 g_object_class_install_property (object_class
,
554 g_param_spec_object ("ui-manager",
556 "GtkUIManager object",
560 g_object_class_install_property (object_class
,
562 g_param_spec_object ("clipboard",
564 "RBShellClipboard object",
565 RB_TYPE_SHELL_CLIPBOARD
,
567 g_object_class_install_property (object_class
,
568 PROP_PLAYLIST_MANAGER
,
569 g_param_spec_object ("playlist-manager",
571 "RBPlaylistManager object",
572 RB_TYPE_PLAYLIST_MANAGER
,
574 g_object_class_install_property (object_class
,
576 g_param_spec_object ("shell-player",
578 "RBShellPlayer object",
579 RB_TYPE_SHELL_PLAYER
,
581 g_object_class_install_property (object_class
,
582 PROP_REMOVABLE_MEDIA_MANAGER
,
583 g_param_spec_object ("removable-media-manager",
584 "RBRemovableMediaManager",
585 "RBRemovableMediaManager object",
586 RB_TYPE_REMOVABLE_MEDIA_MANAGER
,
588 g_object_class_install_property (object_class
,
590 g_param_spec_object ("window",
595 g_object_class_install_property (object_class
,
597 g_param_spec_object ("prefs",
598 "RBShellPreferences",
599 "RBShellPreferences object",
600 RB_TYPE_SHELL_PREFERENCES
,
602 g_object_class_install_property (object_class
,
604 g_param_spec_object ("queue-source",
607 RB_TYPE_PLAY_QUEUE_SOURCE
,
609 g_object_class_install_property (object_class
,
611 g_param_spec_object ("proxy-config",
613 "HTTP proxy configuration",
614 RB_TYPE_PROXY_CONFIG
,
616 g_object_class_install_property (object_class
,
618 g_param_spec_object ("library-source",
621 RB_TYPE_LIBRARY_SOURCE
,
623 g_object_class_install_property (object_class
,
624 PROP_SOURCELIST_MODEL
,
625 g_param_spec_object ("sourcelist-model",
628 RB_TYPE_SOURCELIST_MODEL
,
631 g_object_class_install_property (object_class
,
633 g_param_spec_boolean ("visibility",
635 "Current window visibility",
639 rb_shell_signals
[VISIBILITY_CHANGED
] =
640 g_signal_new ("visibility_changed",
641 G_OBJECT_CLASS_TYPE (object_class
),
643 G_STRUCT_OFFSET (RBShellClass
, visibility_changed
),
645 g_cclosure_marshal_VOID__BOOLEAN
,
650 g_type_class_add_private (klass
, sizeof (RBShellPrivate
));
654 rb_shell_init (RBShell
*shell
)
656 shell
->priv
= RB_SHELL_GET_PRIVATE (shell
);
660 rb_shell_session_init (shell
);
662 eel_gconf_monitor_add (CONF_PREFIX
);
666 rb_shell_set_property (GObject
*object
,
671 RBShell
*shell
= RB_SHELL (object
);
676 shell
->priv
->argc
= g_value_get_int (value
);
679 shell
->priv
->argv
= g_value_get_pointer (value
);
681 case PROP_NO_REGISTRATION
:
682 shell
->priv
->no_registration
= g_value_get_boolean (value
);
685 shell
->priv
->no_update
= g_value_get_boolean (value
);
688 shell
->priv
->dry_run
= g_value_get_boolean (value
);
689 if (shell
->priv
->dry_run
)
690 shell
->priv
->no_registration
= TRUE
;
692 case PROP_RHYTHMDB_FILE
:
693 shell
->priv
->rhythmdb_file
= g_value_dup_string (value
);
695 case PROP_VISIBILITY
:
696 rb_shell_set_visibility (shell
, g_value_get_boolean (value
), FALSE
);
699 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
705 rb_shell_get_property (GObject
*object
,
710 RBShell
*shell
= RB_SHELL (object
);
715 g_value_set_int (value
, shell
->priv
->argc
);
718 g_value_set_pointer (value
, shell
->priv
->argv
);
720 case PROP_NO_REGISTRATION
:
721 g_value_set_boolean (value
, shell
->priv
->no_registration
);
724 g_value_set_boolean (value
, shell
->priv
->no_update
);
727 g_value_set_boolean (value
, shell
->priv
->dry_run
);
729 case PROP_RHYTHMDB_FILE
:
730 g_value_set_string (value
, shell
->priv
->rhythmdb_file
);
733 g_value_set_object (value
, shell
->priv
->db
);
735 case PROP_UI_MANAGER
:
736 g_value_set_object (value
, shell
->priv
->ui_manager
);
739 g_value_set_object (value
, shell
->priv
->clipboard_shell
);
741 case PROP_PLAYLIST_MANAGER
:
742 g_value_set_object (value
, shell
->priv
->playlist_manager
);
744 case PROP_SHELL_PLAYER
:
745 g_value_set_object (value
, shell
->priv
->player_shell
);
747 case PROP_REMOVABLE_MEDIA_MANAGER
:
748 g_value_set_object (value
, shell
->priv
->removable_media_manager
);
750 case PROP_SELECTED_SOURCE
:
751 g_value_set_object (value
, shell
->priv
->selected_source
);
754 g_value_set_object (value
, shell
->priv
->window
);
757 g_value_set_object (value
, shell
->priv
->prefs
);
759 case PROP_QUEUE_SOURCE
:
760 g_value_set_object (value
, shell
->priv
->queue_source
);
762 case PROP_PROXY_CONFIG
:
763 g_value_set_object (value
, shell
->priv
->proxy_config
);
765 case PROP_LIBRARY_SOURCE
:
766 g_value_set_object (value
, shell
->priv
->library_source
);
768 case PROP_SOURCELIST_MODEL
:
770 GtkTreeModel
*model
= NULL
;
772 g_object_get (G_OBJECT (shell
->priv
->sourcelist
), "model", &model
, NULL
);
773 g_value_set_object (value
, model
);
776 case PROP_VISIBILITY
:
777 g_value_set_boolean (value
, rb_shell_get_visibility (shell
));
780 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
786 rb_shell_sync_state (RBShell
*shell
)
788 if (shell
->priv
->dry_run
) {
789 rb_debug ("in dry-run mode, not syncing state");
793 if (!shell
->priv
->load_complete
) {
794 rb_debug ("load incomplete, not syncing state");
798 rb_debug ("saving playlists");
799 rb_playlist_manager_save_playlists (shell
->priv
->playlist_manager
, TRUE
);
801 rb_debug ("saving db");
802 rhythmdb_save (shell
->priv
->db
);
807 idle_save_rhythmdb (RBShell
*shell
)
809 rhythmdb_save (shell
->priv
->db
);
811 shell
->priv
->save_db_id
= 0;
817 idle_save_playlist_manager (RBPlaylistManager
*mgr
)
819 rb_playlist_manager_save_playlists (mgr
, FALSE
);
825 rb_shell_shutdown (RBShell
*shell
)
829 if (shell
->priv
->shutting_down
)
831 shell
->priv
->shutting_down
= TRUE
;
833 /* Hide the main window and tray icon as soon as possible */
834 display
= gtk_widget_get_display (shell
->priv
->window
);
835 gtk_widget_hide (shell
->priv
->window
);
836 gtk_widget_hide (GTK_WIDGET (shell
->priv
->tray_icon
));
837 gdk_display_sync (display
);
841 rb_shell_finalize (GObject
*object
)
843 RBShell
*shell
= RB_SHELL (object
);
845 rb_debug ("Finalizing shell");
847 rb_shell_player_stop (shell
->priv
->player_shell
);
849 eel_gconf_monitor_remove (CONF_PREFIX
);
850 eel_gconf_notification_remove (shell
->priv
->sourcelist_visibility_notify_id
);
851 eel_gconf_notification_remove (shell
->priv
->toolbar_visibility_notify_id
);
852 eel_gconf_notification_remove (shell
->priv
->toolbar_style_notify_id
);
853 eel_gconf_notification_remove (shell
->priv
->smalldisplay_notify_id
);
855 g_list_free (shell
->priv
->supported_media_extensions
);
857 gtk_widget_destroy (GTK_WIDGET (shell
->priv
->tray_icon
));
859 if (shell
->priv
->save_playlist_id
> 0) {
860 g_source_remove (shell
->priv
->save_playlist_id
);
861 shell
->priv
->save_playlist_id
= 0;
864 if (shell
->priv
->save_db_id
> 0) {
865 g_source_remove (shell
->priv
->save_db_id
);
866 shell
->priv
->save_db_id
= 0;
869 rb_debug ("shutting down playlist manager");
870 rb_playlist_manager_shutdown (shell
->priv
->playlist_manager
);
872 rb_debug ("unreffing playlist manager");
873 g_object_unref (G_OBJECT (shell
->priv
->playlist_manager
));
875 rb_debug ("unreffing removable media manager");
876 g_object_unref (G_OBJECT (shell
->priv
->removable_media_manager
));
878 g_object_unref (G_OBJECT (shell
->priv
->proxy_config
));
880 rb_debug ("unreffing clipboard shell");
881 g_object_unref (G_OBJECT (shell
->priv
->clipboard_shell
));
883 rb_debug ("shutting down DB");
884 rhythmdb_shutdown (shell
->priv
->db
);
886 rb_debug ("unreffing DB");
887 g_object_unref (G_OBJECT (shell
->priv
->db
));
889 rb_debug ("destroying prefs");
890 if (shell
->priv
->prefs
!= NULL
)
891 gtk_widget_destroy (shell
->priv
->prefs
);
893 rb_debug ("destroying tooltips");
894 gtk_object_destroy (GTK_OBJECT (shell
->priv
->tooltips
));
896 g_free (shell
->priv
->rhythmdb_file
);
898 rb_debug ("destroying window");
899 gtk_widget_destroy (shell
->priv
->window
);
901 g_list_free (shell
->priv
->sources
);
902 shell
->priv
->sources
= NULL
;
904 g_hash_table_destroy (shell
->priv
->sources_hash
);
906 ((GObjectClass
*)rb_shell_parent_class
)->finalize (G_OBJECT (shell
));
908 rb_debug ("shell shutdown complete");
912 rb_shell_new (int argc
,
914 gboolean no_registration
,
921 s
= g_object_new (RB_TYPE_SHELL
, "argc", argc
, "argv", argv
,
922 "no-registration", no_registration
,
923 "no-update", no_update
,
924 "dry-run", dry_run
, "rhythmdb-file", rhythmdb
, NULL
);
930 construct_db (RBShell
*shell
)
934 /* Initialize the database */
935 rb_debug ("creating database object");
936 rb_profile_start ("creating database object");
938 if (shell
->priv
->rhythmdb_file
)
939 pathname
= g_strdup (shell
->priv
->rhythmdb_file
);
941 pathname
= g_build_filename (rb_dot_dir (), "rhythmdb.xml", NULL
);
943 #ifdef WITH_RHYTHMDB_TREE
944 shell
->priv
->db
= rhythmdb_tree_new (pathname
);
945 #elif defined(WITH_RHYTHMDB_GDA)
946 shell
->priv
->db
= rhythmdb_gda_new (pathname
);
950 if (shell
->priv
->dry_run
)
951 g_object_set (G_OBJECT (shell
->priv
->db
), "dry-run", TRUE
, NULL
);
952 if (shell
->priv
->no_update
)
953 g_object_set (G_OBJECT (shell
->priv
->db
), "no-update", TRUE
, NULL
);
955 g_signal_connect_object (G_OBJECT (shell
->priv
->db
), "load-complete",
956 G_CALLBACK (rb_shell_load_complete_cb
), shell
,
959 rb_profile_end ("creating database object");
963 construct_widgets (RBShell
*shell
)
967 rb_profile_start ("constructing widgets");
970 win
= GTK_WINDOW (gtk_window_new (GTK_WINDOW_TOPLEVEL
));
971 gtk_window_set_title (win
, _("Music Player"));
973 shell
->priv
->window
= GTK_WIDGET (win
);
974 shell
->priv
->iconified
= FALSE
;
975 g_signal_connect_object (G_OBJECT (win
), "window-state-event",
976 G_CALLBACK (rb_shell_window_state_cb
),
979 g_signal_connect_object (G_OBJECT (win
), "configure-event",
980 G_CALLBACK (rb_shell_window_configure_cb
),
983 /* connect after, so that things can affect behaviour */
984 g_signal_connect_object (G_OBJECT (win
), "delete_event",
985 G_CALLBACK (rb_shell_window_delete_cb
),
986 shell
, G_CONNECT_AFTER
);
988 rb_debug ("shell: initializing shell services");
990 shell
->priv
->ui_manager
= gtk_ui_manager_new ();
991 shell
->priv
->source_ui_merge_id
= gtk_ui_manager_new_merge_id (shell
->priv
->ui_manager
);
993 shell
->priv
->player_shell
= rb_shell_player_new (shell
->priv
->db
,
994 shell
->priv
->ui_manager
,
995 shell
->priv
->actiongroup
);
996 g_signal_connect_object (G_OBJECT (shell
->priv
->player_shell
),
997 "playing-source-changed",
998 G_CALLBACK (rb_shell_playing_source_changed_cb
),
1000 g_signal_connect_object (G_OBJECT (shell
->priv
->player_shell
),
1001 "playing-song-changed",
1002 G_CALLBACK (rb_shell_playing_entry_changed_cb
),
1004 g_signal_connect_object (G_OBJECT (shell
->priv
->player_shell
),
1005 "notify::playing-from-queue",
1006 G_CALLBACK (rb_shell_playing_from_queue_cb
),
1008 g_signal_connect_object (G_OBJECT (shell
->priv
->player_shell
),
1009 "window_title_changed",
1010 G_CALLBACK (rb_shell_player_window_title_changed_cb
),
1012 g_signal_connect_object (G_OBJECT (shell
->priv
->player_shell
),
1014 G_CALLBACK (rb_shell_player_elapsed_changed_cb
),
1016 g_signal_connect_object (G_OBJECT (shell
->priv
->player_shell
),
1017 "notify::stream-song",
1018 G_CALLBACK (rb_shell_player_stream_song_changed_cb
),
1020 shell
->priv
->clipboard_shell
= rb_shell_clipboard_new (shell
->priv
->actiongroup
,
1022 shell
->priv
->source_header
= rb_source_header_new (shell
->priv
->ui_manager
,
1023 shell
->priv
->actiongroup
);
1024 gtk_widget_show_all (GTK_WIDGET (shell
->priv
->source_header
));
1026 shell
->priv
->paned
= gtk_hpaned_new ();
1028 shell
->priv
->sourcelist
= rb_sourcelist_new (shell
);
1029 gtk_widget_show_all (shell
->priv
->sourcelist
);
1030 g_signal_connect_object (G_OBJECT (shell
->priv
->sourcelist
), "drop_received",
1031 G_CALLBACK (sourcelist_drag_received_cb
), shell
, 0);
1032 g_signal_connect_object (G_OBJECT (shell
->priv
->sourcelist
), "source_activated",
1033 G_CALLBACK (source_activated_cb
), shell
, 0);
1034 g_signal_connect_object (G_OBJECT (shell
->priv
->sourcelist
), "show_popup",
1035 G_CALLBACK (rb_shell_show_popup_cb
), shell
, 0);
1037 shell
->priv
->statusbar
= rb_statusbar_new (shell
->priv
->db
,
1038 shell
->priv
->actiongroup
);
1039 g_object_set (shell
->priv
->player_shell
, "statusbar", shell
->priv
->statusbar
, NULL
);
1040 gtk_widget_show (GTK_WIDGET (shell
->priv
->statusbar
));
1042 g_signal_connect_object (G_OBJECT (shell
->priv
->sourcelist
), "selected",
1043 G_CALLBACK (source_selected_cb
), shell
, 0);
1045 shell
->priv
->notebook
= gtk_notebook_new ();
1046 gtk_widget_show (shell
->priv
->notebook
);
1047 gtk_notebook_set_show_tabs (GTK_NOTEBOOK (shell
->priv
->notebook
), FALSE
);
1048 gtk_notebook_set_show_border (GTK_NOTEBOOK (shell
->priv
->notebook
), FALSE
);
1049 g_signal_connect_object (G_OBJECT (shell
->priv
->sourcelist
),
1051 G_CALLBACK (paned_size_allocate_cb
),
1054 shell
->priv
->queue_source
= RB_PLAYLIST_SOURCE (rb_play_queue_source_new (shell
));
1055 g_object_set (G_OBJECT(shell
->priv
->player_shell
), "queue-source", shell
->priv
->queue_source
, NULL
);
1056 g_object_set (G_OBJECT(shell
->priv
->clipboard_shell
), "queue-source", shell
->priv
->queue_source
, NULL
);
1057 rb_shell_append_source (shell
, RB_SOURCE (shell
->priv
->queue_source
), NULL
);
1058 g_object_get (G_OBJECT (shell
->priv
->queue_source
), "sidebar", &shell
->priv
->queue_sidebar
, NULL
);
1059 gtk_widget_show_all (shell
->priv
->queue_sidebar
);
1060 gtk_widget_set_no_show_all (shell
->priv
->queue_sidebar
, TRUE
);
1062 /* places for plugins to put UI */
1063 shell
->priv
->top_container
= GTK_BOX (gtk_vbox_new (FALSE
, 0));
1064 shell
->priv
->bottom_container
= GTK_BOX (gtk_vbox_new (FALSE
, 0));
1065 shell
->priv
->sidebar_container
= GTK_BOX (gtk_vbox_new (FALSE
, 0));
1067 /* set up sidebars */
1068 shell
->priv
->paned
= gtk_hpaned_new ();
1070 GtkWidget
*vbox2
= gtk_vbox_new (FALSE
, 0);
1072 shell
->priv
->queue_paned
= gtk_vpaned_new ();
1073 gtk_paned_pack1 (GTK_PANED (shell
->priv
->queue_paned
),
1074 shell
->priv
->sourcelist
,
1076 gtk_paned_pack2 (GTK_PANED (shell
->priv
->queue_paned
),
1077 shell
->priv
->queue_sidebar
,
1079 gtk_container_child_set (GTK_CONTAINER (shell
->priv
->queue_paned
),
1080 GTK_WIDGET (shell
->priv
->queue_sidebar
),
1084 gtk_box_pack_start (GTK_BOX (vbox2
),
1085 GTK_WIDGET (shell
->priv
->source_header
),
1087 gtk_box_pack_start (GTK_BOX (vbox2
),
1088 shell
->priv
->notebook
,
1091 gtk_box_pack_start_defaults (shell
->priv
->sidebar_container
, shell
->priv
->queue_paned
);
1092 gtk_paned_pack1 (GTK_PANED (shell
->priv
->paned
),
1093 GTK_WIDGET (shell
->priv
->sidebar_container
),
1095 gtk_paned_pack2 (GTK_PANED (shell
->priv
->paned
),
1098 gtk_widget_show (vbox2
);
1101 g_signal_connect_object (G_OBJECT (shell
->priv
->queue_paned
),
1103 G_CALLBACK (sidebar_paned_size_allocate_cb
),
1105 gtk_widget_show (shell
->priv
->paned
);
1107 shell
->priv
->main_vbox
= gtk_vbox_new (FALSE
, 0);
1108 gtk_container_set_border_width (GTK_CONTAINER (shell
->priv
->main_vbox
), 0);
1109 gtk_box_pack_start (GTK_BOX (shell
->priv
->main_vbox
), GTK_WIDGET (shell
->priv
->player_shell
), FALSE
, TRUE
, 6);
1110 gtk_widget_show (GTK_WIDGET (shell
->priv
->player_shell
));
1112 gtk_box_pack_start (GTK_BOX (shell
->priv
->main_vbox
), GTK_WIDGET (shell
->priv
->top_container
), FALSE
, TRUE
, 0);
1113 gtk_box_pack_start (GTK_BOX (shell
->priv
->main_vbox
), shell
->priv
->paned
, TRUE
, TRUE
, 0);
1114 gtk_box_pack_start (GTK_BOX (shell
->priv
->main_vbox
), GTK_WIDGET (shell
->priv
->bottom_container
), FALSE
, TRUE
, 0);
1115 gtk_box_pack_start (GTK_BOX (shell
->priv
->main_vbox
), GTK_WIDGET (shell
->priv
->statusbar
), FALSE
, TRUE
, 0);
1116 gtk_widget_show_all (shell
->priv
->main_vbox
);
1118 gtk_container_add (GTK_CONTAINER (win
), shell
->priv
->main_vbox
);
1120 shell
->priv
->proxy_config
= rb_proxy_config_new ();
1122 rb_profile_end ("constructing widgets");
1126 construct_sources (RBShell
*shell
)
1128 rb_profile_start ("constructing sources");
1130 shell
->priv
->library_source
= RB_LIBRARY_SOURCE (rb_library_source_new (shell
));
1131 rb_shell_append_source (shell
, RB_SOURCE (shell
->priv
->library_source
), NULL
);
1132 shell
->priv
->iradio_source
= RB_IRADIO_SOURCE (rb_iradio_source_new (shell
));
1133 rb_shell_append_source (shell
, RB_SOURCE (shell
->priv
->iradio_source
), NULL
);
1134 shell
->priv
->podcast_source
= RB_PODCAST_SOURCE (rb_podcast_source_new (shell
));
1135 rb_shell_append_source (shell
, RB_SOURCE (shell
->priv
->podcast_source
), NULL
);
1137 shell
->priv
->missing_files_source
= rb_missing_files_source_new (shell
, shell
->priv
->library_source
);
1138 rb_shell_append_source (shell
, shell
->priv
->missing_files_source
, RB_SOURCE (shell
->priv
->library_source
));
1139 shell
->priv
->import_errors_source
= rb_import_errors_source_new (shell
, shell
->priv
->library_source
);
1140 rb_shell_append_source (shell
, shell
->priv
->import_errors_source
, RB_SOURCE (shell
->priv
->library_source
));
1142 /* Initialize playlist manager */
1143 rb_debug ("shell: creating playlist manager");
1144 shell
->priv
->playlist_manager
= rb_playlist_manager_new (shell
,
1145 RB_SOURCELIST (shell
->priv
->sourcelist
));
1147 g_signal_connect_object (G_OBJECT (shell
->priv
->playlist_manager
), "playlist_added",
1148 G_CALLBACK (rb_shell_playlist_added_cb
), shell
, 0);
1149 g_signal_connect_object (G_OBJECT (shell
->priv
->playlist_manager
), "playlist_created",
1150 G_CALLBACK (rb_shell_playlist_created_cb
), shell
, 0);
1152 #ifdef WITH_DAAP_SUPPORT
1153 rb_daap_sources_init (shell
);
1154 if (!shell
->priv
->no_registration
)
1155 rb_daap_sharing_init (shell
);
1158 /* Initialize removable media manager */
1159 rb_debug ("shell: creating removable media manager");
1160 shell
->priv
->removable_media_manager
= rb_removable_media_manager_new (shell
,
1161 RB_SOURCELIST (shell
->priv
->sourcelist
));
1163 g_signal_connect_object (G_OBJECT (shell
->priv
->removable_media_manager
), "medium_added",
1164 G_CALLBACK (rb_shell_medium_added_cb
), shell
, 0);
1165 g_signal_connect_object (G_OBJECT (shell
->priv
->removable_media_manager
), "transfer-progress",
1166 G_CALLBACK (rb_shell_transfer_progress_cb
), shell
, 0);
1168 rb_profile_end ("constructing sources");
1172 construct_load_ui (RBShell
*shell
)
1177 GtkToolItem
*tool_item
;
1178 GError
*error
= NULL
;
1180 rb_debug ("shell: loading ui");
1181 rb_profile_start ("loading ui");
1183 gtk_ui_manager_insert_action_group (shell
->priv
->ui_manager
,
1184 shell
->priv
->actiongroup
, 0);
1185 gtk_ui_manager_add_ui_from_file (shell
->priv
->ui_manager
,
1186 rb_file ("rhythmbox-ui.xml"), &error
);
1188 gtk_ui_manager_ensure_update (shell
->priv
->ui_manager
);
1189 gtk_window_add_accel_group (GTK_WINDOW (shell
->priv
->window
),
1190 gtk_ui_manager_get_accel_group (shell
->priv
->ui_manager
));
1191 menubar
= gtk_ui_manager_get_widget (shell
->priv
->ui_manager
, "/MenuBar");
1193 gtk_box_pack_start (GTK_BOX (shell
->priv
->main_vbox
), menubar
, FALSE
, FALSE
, 0);
1194 gtk_box_reorder_child (GTK_BOX (shell
->priv
->main_vbox
), menubar
, 0);
1196 hbox
= gtk_hbox_new (FALSE
, 0);
1197 gtk_box_pack_start (GTK_BOX (shell
->priv
->main_vbox
), hbox
, FALSE
, FALSE
, 0);
1198 gtk_box_reorder_child (GTK_BOX (shell
->priv
->main_vbox
), hbox
, 1);
1200 toolbar
= gtk_ui_manager_get_widget (shell
->priv
->ui_manager
, "/ToolBar");
1201 gtk_box_pack_start_defaults (GTK_BOX (hbox
), toolbar
);
1203 shell
->priv
->volume_button
= bacon_volume_button_new (GTK_ICON_SIZE_LARGE_TOOLBAR
,
1205 g_signal_connect (shell
->priv
->volume_button
, "value-changed",
1206 G_CALLBACK (rb_shell_volume_widget_changed_cb
),
1208 g_signal_connect (shell
->priv
->player_shell
, "notify::volume",
1209 G_CALLBACK (rb_shell_player_volume_changed_cb
),
1211 rb_shell_player_volume_changed_cb (shell
->priv
->player_shell
, NULL
, shell
);
1213 tool_item
= gtk_tool_item_new ();
1214 gtk_tool_item_set_expand (tool_item
, TRUE
);
1215 gtk_widget_show (GTK_WIDGET (tool_item
));
1216 gtk_toolbar_insert (GTK_TOOLBAR (toolbar
), tool_item
, -1);
1218 tool_item
= gtk_tool_item_new ();
1219 gtk_container_add (GTK_CONTAINER (tool_item
), shell
->priv
->volume_button
);
1220 gtk_widget_show_all (GTK_WIDGET (tool_item
));
1221 gtk_toolbar_insert (GTK_TOOLBAR (toolbar
), tool_item
, -1);
1223 gtk_widget_show (hbox
);
1225 shell
->priv
->tooltips
= gtk_tooltips_new ();
1226 gtk_tooltips_enable (shell
->priv
->tooltips
);
1228 gtk_tooltips_set_tip (GTK_TOOLTIPS (shell
->priv
->tooltips
),
1229 GTK_WIDGET (shell
->priv
->volume_button
),
1230 _("Change the music volume"), NULL
);
1232 if (error
!= NULL
) {
1233 g_warning ("Couldn't merge %s: %s",
1234 rb_file ("rhythmbox-ui.xml"), error
->message
);
1235 g_clear_error (&error
);
1238 rb_profile_end ("loading ui");
1242 rb_shell_constructor (GType type
,
1243 guint n_construct_properties
,
1244 GObjectConstructParam
*construct_properties
)
1248 shell
= RB_SHELL (((GObjectClass
*)rb_shell_parent_class
)
1249 ->constructor (type
, n_construct_properties
, construct_properties
));
1251 rb_debug ("Constructing shell");
1252 rb_profile_start ("constructing shell");
1254 shell
->priv
->actiongroup
= gtk_action_group_new ("MainActions");
1255 gtk_action_group_set_translation_domain (shell
->priv
->actiongroup
,
1257 gtk_action_group_add_actions (shell
->priv
->actiongroup
,
1259 rb_shell_n_actions
, shell
);
1260 gtk_action_group_add_toggle_actions (shell
->priv
->actiongroup
,
1261 rb_shell_toggle_entries
,
1262 rb_shell_n_toggle_entries
,
1265 construct_db (shell
);
1267 /* initialize shell services */
1268 construct_widgets (shell
);
1270 rb_debug ("shell: setting up tray icon");
1271 tray_destroy_cb (NULL
, shell
);
1273 rb_debug ("shell: adding gconf notification");
1275 shell
->priv
->sourcelist_visibility_notify_id
=
1276 eel_gconf_notification_add (CONF_UI_SOURCELIST_HIDDEN
,
1277 (GConfClientNotifyFunc
) sourcelist_visibility_changed_cb
,
1279 shell
->priv
->toolbar_visibility_notify_id
=
1280 eel_gconf_notification_add (CONF_UI_TOOLBAR_HIDDEN
,
1281 (GConfClientNotifyFunc
) toolbar_state_changed_cb
,
1283 shell
->priv
->toolbar_style_notify_id
=
1284 eel_gconf_notification_add (CONF_UI_TOOLBAR_STYLE
,
1285 (GConfClientNotifyFunc
) toolbar_state_changed_cb
,
1287 shell
->priv
->smalldisplay_notify_id
=
1288 eel_gconf_notification_add (CONF_UI_SMALL_DISPLAY
,
1289 (GConfClientNotifyFunc
) smalldisplay_changed_cb
,
1292 /* read the cached copies of the gconf keys */
1293 shell
->priv
->window_width
= eel_gconf_get_integer (CONF_STATE_WINDOW_WIDTH
);
1294 shell
->priv
->window_height
= eel_gconf_get_integer (CONF_STATE_WINDOW_HEIGHT
);
1295 shell
->priv
->small_width
= eel_gconf_get_integer (CONF_STATE_SMALL_WIDTH
);
1296 shell
->priv
->window_maximised
= eel_gconf_get_boolean (CONF_STATE_WINDOW_MAXIMIZED
);
1297 shell
->priv
->window_small
= eel_gconf_get_boolean (CONF_UI_SMALL_DISPLAY
);
1298 shell
->priv
->queue_as_sidebar
= eel_gconf_get_boolean (CONF_UI_QUEUE_AS_SIDEBAR
);
1299 shell
->priv
->window_x
= eel_gconf_get_integer (CONF_STATE_WINDOW_X_POSITION
);
1300 shell
->priv
->window_y
= eel_gconf_get_integer (CONF_STATE_WINDOW_Y_POSITION
);
1301 shell
->priv
->paned_position
= eel_gconf_get_integer (CONF_STATE_PANED_POSITION
);
1302 shell
->priv
->sourcelist_height
= eel_gconf_get_integer (CONF_STATE_SOURCELIST_HEIGHT
);
1303 shell
->priv
->statusbar_hidden
= eel_gconf_get_boolean (CONF_UI_STATUSBAR_HIDDEN
);
1306 rb_debug ("shell: syncing with gconf");
1307 rb_shell_sync_sourcelist_visibility (shell
);
1308 rb_shell_sync_pane_visibility (shell
);
1310 g_signal_connect_object (G_OBJECT (shell
->priv
->db
), "save-error",
1311 G_CALLBACK (rb_shell_db_save_error_cb
), shell
, 0);
1312 g_signal_connect_object (G_OBJECT (shell
->priv
->db
), "entry-added",
1313 G_CALLBACK (rb_shell_db_entry_added_cb
), shell
, 0);
1315 construct_sources (shell
);
1317 construct_load_ui (shell
);
1319 rb_shell_sync_window_state (shell
, FALSE
);
1320 rb_shell_sync_smalldisplay (shell
);
1321 rb_shell_sync_party_mode (shell
);
1322 rb_shell_sync_toolbar_state (shell
);
1324 rb_shell_select_source (shell
, RB_SOURCE (shell
->priv
->library_source
));
1326 rb_plugins_engine_init (shell
);
1329 rb_debug ("loading database");
1330 rhythmdb_load (shell
->priv
->db
);
1332 rb_debug ("shell: syncing window state");
1333 rb_shell_sync_paned (shell
);
1334 gtk_widget_show_all (GTK_WIDGET (shell
->priv
->tray_icon
));
1336 /* Stop here if this is the first time. */
1337 if (!eel_gconf_get_boolean (CONF_FIRST_TIME
)) {
1339 druid
= rb_druid_new (shell
->priv
->db
);
1340 g_signal_connect (G_OBJECT (druid
),
1342 G_CALLBACK (rb_shell_druid_response_cb
),
1345 gtk_widget_show_all (GTK_WIDGET (druid
));
1347 rb_shell_set_visibility (shell
, eel_gconf_get_boolean (CONF_STATE_WINDOW_VISIBLE
), TRUE
);
1348 gdk_notify_startup_complete ();
1351 /* focus play if small, the entry view if not */
1352 if (shell
->priv
->window_small
) {
1353 GtkWidget
*play_button
;
1355 play_button
= gtk_ui_manager_get_widget (shell
->priv
->ui_manager
, "/ToolBar/Play");
1356 gtk_widget_grab_focus (play_button
);
1360 view
= rb_source_get_entry_view (RB_SOURCE (shell
->priv
->library_source
));
1361 gtk_widget_grab_focus (GTK_WIDGET (view
));
1364 rb_profile_end ("constructing shell");
1366 return G_OBJECT (shell
);
1369 /* Based on a function found in wnck */
1371 set_icon_geometry (GdkWindow
*window
,
1378 Display
*dpy
= gdk_x11_drawable_get_xdisplay (window
);
1385 XChangeProperty (dpy
,
1386 GDK_WINDOW_XID (window
),
1387 gdk_x11_get_xatom_by_name_for_display (gdk_drawable_get_display (window
),
1388 "_NET_WM_ICON_GEOMETRY"),
1389 XA_CARDINAL
, 32, PropModeReplace
,
1390 (guchar
*)&data
, 4);
1394 rb_shell_window_state_cb (GtkWidget
*widget
,
1395 GdkEventWindowState
*event
,
1398 shell
->priv
->iconified
= ((event
->new_window_state
& GDK_WINDOW_STATE_ICONIFIED
) != 0);
1400 if (event
->changed_mask
& (GDK_WINDOW_STATE_WITHDRAWN
| GDK_WINDOW_STATE_ICONIFIED
)) {
1401 g_signal_emit (shell
, rb_shell_signals
[VISIBILITY_CHANGED
], 0,
1402 rb_shell_get_visibility (shell
));
1405 /* don't save maximized state when is hidden */
1406 if (!GTK_WIDGET_VISIBLE(shell
->priv
->window
))
1409 if (event
->changed_mask
& GDK_WINDOW_STATE_MAXIMIZED
) {
1410 gboolean maximised
= ((event
->new_window_state
& GDK_WINDOW_STATE_MAXIMIZED
) != 0);
1412 gtk_statusbar_set_has_resize_grip (GTK_STATUSBAR (shell
->priv
->statusbar
),
1414 if (!shell
->priv
->window_small
) {
1415 shell
->priv
->window_maximised
= maximised
;
1416 eel_gconf_set_boolean (CONF_STATE_WINDOW_MAXIMIZED
,
1417 shell
->priv
->window_maximised
);
1419 rb_shell_sync_window_state (shell
, TRUE
);
1420 rb_shell_sync_paned (shell
);
1427 rb_shell_get_visibility (RBShell
*shell
)
1429 GdkWindowState state
;
1431 if (!GTK_WIDGET_REALIZED (shell
->priv
->window
))
1433 if (shell
->priv
->iconified
)
1436 state
= gdk_window_get_state (GTK_WIDGET (shell
->priv
->window
)->window
);
1437 if (state
& (GDK_WINDOW_STATE_WITHDRAWN
| GDK_WINDOW_STATE_ICONIFIED
))
1444 idle_hide_mainwindow (gpointer data
)
1446 RBShell
*shell
= RB_SHELL (data
);
1448 GDK_THREADS_ENTER ();
1450 gtk_widget_hide (GTK_WIDGET (shell
->priv
->window
));
1452 g_signal_emit (shell
, rb_shell_signals
[VISIBILITY_CHANGED
], 0, FALSE
);
1454 g_object_unref (shell
);
1456 GDK_THREADS_LEAVE ();
1462 rb_shell_set_visibility (RBShell
*shell
,
1466 gboolean current_visible
;
1468 rb_profile_start ("changing shell visibility");
1470 current_visible
= rb_shell_get_visibility (shell
);
1471 if (!force
&& visible
== current_visible
) {
1472 rb_profile_end ("changing shell visibility");
1476 /* FIXME - see below */
1477 if (shell
->priv
->idle_hide_mainwindow_id
> 0)
1478 g_source_remove (shell
->priv
->idle_hide_mainwindow_id
);
1479 shell
->priv
->idle_hide_mainwindow_id
= 0;
1481 /* don't minimise if we have no tray icon */
1482 if (visible
|| (!force
&& !egg_tray_icon_have_manager (EGG_TRAY_ICON (shell
->priv
->tray_icon
)))) {
1483 rb_debug ("showing main window");
1484 rb_shell_sync_window_state (shell
, FALSE
);
1486 if (egg_tray_icon_have_manager (EGG_TRAY_ICON (shell
->priv
->tray_icon
)))
1487 gtk_window_set_skip_taskbar_hint (GTK_WINDOW (shell
->priv
->window
), FALSE
);
1488 gtk_widget_show (GTK_WIDGET (shell
->priv
->window
));
1489 gtk_window_deiconify (GTK_WINDOW (shell
->priv
->window
));
1491 if (GTK_WIDGET_REALIZED (GTK_WIDGET (shell
->priv
->window
)))
1492 rb_shell_present (shell
, gtk_get_current_event_time (), NULL
);
1494 gtk_widget_show_all (GTK_WIDGET (shell
->priv
->window
));
1496 g_signal_emit (shell
, rb_shell_signals
[VISIBILITY_CHANGED
], 0, visible
);
1498 eel_gconf_set_boolean (CONF_STATE_WINDOW_VISIBLE
, TRUE
);
1500 int x
, y
, width
, height
;
1502 rb_debug ("hiding main window");
1503 shell
->priv
->iconified
= TRUE
;
1504 rb_tray_icon_get_geom (shell
->priv
->tray_icon
,
1505 &x
, &y
, &width
, &height
);
1506 if (GTK_WIDGET_REALIZED (GTK_WIDGET (shell
->priv
->window
)))
1507 set_icon_geometry (GTK_WIDGET (shell
->priv
->window
)->window
,
1508 x
, y
, width
, height
);
1509 if (egg_tray_icon_have_manager (EGG_TRAY_ICON (shell
->priv
->tray_icon
)))
1510 gtk_window_set_skip_taskbar_hint (GTK_WINDOW (shell
->priv
->window
), TRUE
);
1511 gtk_window_iconify (GTK_WINDOW (shell
->priv
->window
));
1513 /* FIMXE - this is horribly evil racy workaround for a
1514 * current bug in the tasklist not noticing our hint
1517 shell
->priv
->idle_hide_mainwindow_id
=
1518 g_timeout_add (250, idle_hide_mainwindow
, g_object_ref (shell
));
1520 eel_gconf_set_boolean (CONF_STATE_WINDOW_VISIBLE
, FALSE
);
1523 rb_profile_end ("changing shell visibility");
1527 rb_shell_window_configure_cb (GtkWidget
*win
,
1528 GdkEventConfigure
*event
,
1531 if (shell
->priv
->window_small
) {
1532 rb_debug ("storing small window width of %d", event
->width
);
1533 shell
->priv
->small_width
= event
->width
;
1534 eel_gconf_set_integer (CONF_STATE_SMALL_WIDTH
, event
->width
);
1535 } else if (!shell
->priv
->window_maximised
&& !shell
->priv
->iconified
) {
1536 rb_debug ("storing window size of %d:%d", event
->width
, event
->height
);
1537 shell
->priv
->window_width
= event
->width
;
1538 shell
->priv
->window_height
= event
->height
;
1539 eel_gconf_set_integer (CONF_STATE_WINDOW_WIDTH
, event
->width
);
1540 eel_gconf_set_integer (CONF_STATE_WINDOW_HEIGHT
, event
->height
);
1543 if (shell
->priv
->window_small
|| !shell
->priv
->window_maximised
) {
1544 gtk_window_get_position (GTK_WINDOW(shell
->priv
->window
),
1545 &shell
->priv
->window_x
,
1546 &shell
->priv
->window_y
);
1548 eel_gconf_set_integer (CONF_STATE_WINDOW_X_POSITION
, shell
->priv
->window_x
);
1549 eel_gconf_set_integer (CONF_STATE_WINDOW_Y_POSITION
, shell
->priv
->window_y
);
1556 rb_shell_window_delete_cb (GtkWidget
*win
,
1560 if (shell
->priv
->party_mode
) {
1564 rb_shell_quit (shell
);
1570 rb_shell_sync_window_state (RBShell
*shell
,
1571 gboolean dont_maximise
)
1575 rb_profile_start ("syncing window state");
1577 if (shell
->priv
->window_small
) {
1578 hints
.min_height
= -1;
1579 hints
.min_width
= -1;
1580 hints
.max_height
= -1;
1581 hints
.max_width
= 3000;
1582 gtk_window_set_default_size (GTK_WINDOW (shell
->priv
->window
),
1583 shell
->priv
->small_width
, 0);
1584 gtk_window_resize (GTK_WINDOW (shell
->priv
->window
),
1585 shell
->priv
->small_width
, 1);
1586 gtk_window_set_geometry_hints (GTK_WINDOW (shell
->priv
->window
),
1589 GDK_HINT_MIN_SIZE
| GDK_HINT_MAX_SIZE
);
1590 gtk_window_unmaximize (GTK_WINDOW (shell
->priv
->window
));
1591 rb_debug ("syncing small window width to %d", shell
->priv
->small_width
);
1593 if (!dont_maximise
) {
1594 if (shell
->priv
->window_maximised
)
1595 gtk_window_maximize (GTK_WINDOW (shell
->priv
->window
));
1597 gtk_window_unmaximize (GTK_WINDOW (shell
->priv
->window
));
1600 gtk_window_set_default_size (GTK_WINDOW (shell
->priv
->window
),
1601 shell
->priv
->window_width
,
1602 shell
->priv
->window_height
);
1603 gtk_window_resize (GTK_WINDOW (shell
->priv
->window
),
1604 shell
->priv
->window_width
,
1605 shell
->priv
->window_height
);
1606 gtk_window_set_geometry_hints (GTK_WINDOW (shell
->priv
->window
),
1612 gtk_window_move (GTK_WINDOW (shell
->priv
->window
),
1613 shell
->priv
->window_x
,
1614 shell
->priv
->window_y
);
1615 rb_profile_end ("syncing window state");
1619 source_selected_cb (RBSourceList
*sourcelist
,
1623 rb_debug ("source selected");
1624 rb_shell_select_source (shell
, source
);
1628 source_activated_cb (RBSourceList
*sourcelist
,
1632 rb_debug ("source activated");
1634 /* Stop the playing source, if any */
1635 rb_shell_player_set_playing_source (shell
->priv
->player_shell
, NULL
);
1637 /* Select the new one, and start it playing */
1638 rb_shell_select_source (shell
, source
);
1639 rb_shell_player_set_playing_source (shell
->priv
->player_shell
, source
);
1640 /* Ignore error from here */
1641 rb_shell_player_playpause (shell
->priv
->player_shell
, FALSE
, NULL
);
1645 rb_shell_db_save_error_cb (RhythmDB
*db
,
1646 const char *uri
, const GError
*error
,
1649 rb_error_dialog (GTK_WINDOW (shell
->priv
->window
),
1650 _("Error while saving song information"),
1651 "%s", error
->message
);
1655 rb_shell_db_entry_added_cb (RhythmDB
*db
,
1656 RhythmDBEntry
*entry
,
1659 if (shell
->priv
->pending_entry
== NULL
)
1662 rb_debug ("got entry added for %s", entry
->location
);
1663 if (strcmp (entry
->location
, shell
->priv
->pending_entry
) == 0) {
1664 rb_shell_play_entry (shell
, entry
);
1666 g_free (shell
->priv
->pending_entry
);
1667 shell
->priv
->pending_entry
= NULL
;
1672 rb_shell_get_source_by_entry_type (RBShell
*shell
,
1673 RhythmDBEntryType type
)
1675 return g_hash_table_lookup (shell
->priv
->sources_hash
, type
);
1679 rb_shell_register_entry_type_for_source (RBShell
*shell
,
1681 RhythmDBEntryType type
)
1683 if (shell
->priv
->sources_hash
== NULL
) {
1684 shell
->priv
->sources_hash
= g_hash_table_new (g_direct_hash
,
1687 g_assert (g_hash_table_lookup (shell
->priv
->sources_hash
, type
) == NULL
);
1688 g_hash_table_insert (shell
->priv
->sources_hash
, type
, source
);
1694 rb_shell_append_source (RBShell
*shell
,
1698 shell
->priv
->sources
1699 = g_list_append (shell
->priv
->sources
, source
);
1701 g_signal_connect_object (G_OBJECT (source
), "deleted",
1702 G_CALLBACK (rb_shell_source_deleted_cb
), shell
, 0);
1704 gtk_notebook_append_page (GTK_NOTEBOOK (shell
->priv
->notebook
),
1705 GTK_WIDGET (source
),
1706 gtk_label_new (""));
1707 gtk_widget_show (GTK_WIDGET (source
));
1709 rb_sourcelist_append (RB_SOURCELIST (shell
->priv
->sourcelist
),
1714 rb_shell_playlist_added_cb (RBPlaylistManager
*mgr
,
1718 rb_shell_append_source (shell
, source
, NULL
);
1722 rb_shell_playlist_created_cb (RBPlaylistManager
*mgr
,
1726 shell
->priv
->window_small
= FALSE
;
1727 eel_gconf_set_boolean (CONF_UI_SMALL_DISPLAY
, shell
->priv
->window_small
);
1728 eel_gconf_set_boolean (CONF_UI_SOURCELIST_HIDDEN
, shell
->priv
->window_small
);
1730 rb_shell_sync_window_state (shell
, FALSE
);
1734 rb_shell_medium_added_cb (RBRemovableMediaManager
*mgr
,
1738 rb_shell_append_source (shell
, source
, NULL
);
1742 rb_shell_transfer_progress_cb (RBRemovableMediaManager
*mgr
,
1748 rb_debug ("transferred %d tracks out of %d", done
, total
);
1754 s
= g_strdup_printf (_("Transferring track %d out of %d (%.0f%%)"),
1755 done
+ 1, total
, fraction
* 100);
1757 s
= g_strdup_printf (_("Transferring track %d out of %d"),
1760 rb_statusbar_set_progress (shell
->priv
->statusbar
,
1761 (((double)(done
) + fraction
)/total
),
1764 rb_statusbar_set_progress (shell
->priv
->statusbar
, -1, NULL
);
1769 rb_shell_source_deleted_cb (RBSource
*source
,
1772 rb_debug ("source deleted");
1774 if (source
== rb_shell_player_get_playing_source (shell
->priv
->player_shell
)) {
1775 rb_shell_player_set_playing_source (shell
->priv
->player_shell
, NULL
);
1777 if (source
== shell
->priv
->selected_source
) {
1778 if (source
!= RB_SOURCE (shell
->priv
->library_source
))
1779 rb_shell_select_source (shell
, RB_SOURCE (shell
->priv
->library_source
));
1781 rb_shell_select_source (shell
, NULL
);
1784 shell
->priv
->sources
= g_list_remove (shell
->priv
->sources
, source
);
1786 rb_sourcelist_remove (RB_SOURCELIST (shell
->priv
->sourcelist
), source
);
1788 gtk_notebook_remove_page (GTK_NOTEBOOK (shell
->priv
->notebook
),
1789 gtk_notebook_page_num (GTK_NOTEBOOK (shell
->priv
->notebook
),
1790 GTK_WIDGET (source
)));
1794 rb_shell_playing_source_changed_cb (RBShellPlayer
*player
,
1798 rb_debug ("playing source changed");
1799 if (source
!= RB_SOURCE (shell
->priv
->queue_source
))
1800 rb_sourcelist_set_playing_source (RB_SOURCELIST (shell
->priv
->sourcelist
),
1805 rb_shell_playing_from_queue_cb (RBShellPlayer
*player
,
1809 gboolean from_queue
;
1810 g_object_get (G_OBJECT (player
), "playing-from-queue", &from_queue
, NULL
);
1811 if (!shell
->priv
->queue_as_sidebar
) {
1812 rb_sourcelist_set_playing_source (RB_SOURCELIST (shell
->priv
->sourcelist
),
1813 rb_shell_player_get_playing_source (shell
->priv
->player_shell
));
1817 RhythmDBEntry
*entry
;
1818 RhythmDBEntryType entry_type
;
1820 /* if playing from the queue, show the playing entry as playing in the
1821 * registered source for its type, so it makes sense when 'jump to current'
1822 * jumps to it there.
1824 entry
= rb_shell_player_get_playing_entry (shell
->priv
->player_shell
);
1828 entry_type
= rhythmdb_entry_get_entry_type (entry
);
1829 source
= rb_shell_get_source_by_entry_type (shell
, entry_type
);
1830 songs
= rb_source_get_entry_view (source
);
1832 rb_entry_view_set_state (songs
, from_queue
? RB_ENTRY_VIEW_PLAYING
: RB_ENTRY_VIEW_NOT_PLAYING
);
1833 rb_sourcelist_set_playing_source (RB_SOURCELIST (shell
->priv
->sourcelist
),
1834 rb_shell_player_get_active_source (shell
->priv
->player_shell
));
1839 rb_shell_playing_entry_changed_cb (RBShellPlayer
*player
,
1840 RhythmDBEntry
*entry
,
1843 /* RBRemoteSong song; */
1846 /* emit remote song_changed notification */
1848 song.title = g_strdup (rb_refstring_get (entry->title));
1849 song.artist = g_strdup (rb_refstring_get (entry->artist));
1850 song.genre = g_strdup (rb_refstring_get (entry->genre));
1851 song.album = g_strdup (rb_refstring_get (entry->album));
1852 song.uri = g_strdup (entry->location);
1854 song.track_number = entry->tracknum;
1855 song.disc_number = entry->discnum;
1856 song.duration = entry->duration;
1857 song.bitrate = entry->bitrate;
1858 song.filesize = entry->file_size;
1859 song.rating = entry->rating;
1860 song.play_count = entry->play_count;
1861 song.last_played = entry->last_played;
1863 g_signal_emit_by_name (RB_REMOTE_PROXY (shell), "song_changed", &song);
1866 /* Translators: by Artist from Album*/
1867 notifytitle
= g_strdup_printf (_("by %s from %s"),
1868 rhythmdb_entry_get_string (entry
, RHYTHMDB_PROP_ARTIST
),
1869 rhythmdb_entry_get_string (entry
, RHYTHMDB_PROP_ALBUM
));
1870 rb_shell_hidden_notify (shell
,
1872 rhythmdb_entry_get_string (entry
, RHYTHMDB_PROP_TITLE
),
1875 g_free (notifytitle
);
1879 merge_source_ui_cb (const char *action
,
1882 gtk_ui_manager_add_ui (shell
->priv
->ui_manager
,
1883 shell
->priv
->source_ui_merge_id
,
1887 GTK_UI_MANAGER_AUTO
,
1892 rb_shell_select_source (RBShell
*shell
,
1897 if (shell
->priv
->selected_source
== source
)
1900 rb_debug ("selecting source %p", source
);
1902 if (shell
->priv
->selected_source
) {
1903 rb_source_deactivate (shell
->priv
->selected_source
);
1904 gtk_ui_manager_remove_ui (shell
->priv
->ui_manager
, shell
->priv
->source_ui_merge_id
);
1907 shell
->priv
->selected_source
= source
;
1908 rb_source_activate (shell
->priv
->selected_source
);
1911 gtk_notebook_set_current_page (GTK_NOTEBOOK (shell
->priv
->notebook
),
1912 gtk_notebook_page_num (GTK_NOTEBOOK (shell
->priv
->notebook
), GTK_WIDGET (source
)));
1914 g_signal_handlers_block_by_func (G_OBJECT (shell
->priv
->sourcelist
),
1915 G_CALLBACK (source_selected_cb
),
1917 rb_sourcelist_select (RB_SOURCELIST (shell
->priv
->sourcelist
),
1919 g_signal_handlers_unblock_by_func (G_OBJECT (shell
->priv
->sourcelist
),
1920 G_CALLBACK (source_selected_cb
),
1923 /* update services */
1924 rb_shell_clipboard_set_source (shell
->priv
->clipboard_shell
, source
);
1925 rb_shell_player_set_selected_source (shell
->priv
->player_shell
, source
);
1926 rb_source_header_set_source (shell
->priv
->source_header
, source
);
1927 rb_statusbar_set_source (shell
->priv
->statusbar
, source
);
1928 g_object_set (G_OBJECT (shell
->priv
->playlist_manager
), "source", source
, NULL
);
1929 g_object_set (G_OBJECT (shell
->priv
->removable_media_manager
), "source", source
, NULL
);
1931 /* merge the source-specific UI */
1932 actions
= rb_source_get_ui_actions (source
);
1933 g_list_foreach (actions
, (GFunc
)merge_source_ui_cb
, shell
);
1934 rb_list_deep_free (actions
);
1938 rb_shell_player_window_title_changed_cb (RBShellPlayer
*player
,
1939 const char *window_title
,
1942 rb_shell_set_window_title (shell
, window_title
);
1946 rb_shell_player_elapsed_changed_cb (RBShellPlayer
*player
,
1950 rb_shell_set_elapsed (shell
, elapsed
);
1954 rb_shell_player_stream_song_changed_cb (RBShellPlayer
*player
,
1959 g_object_get (G_OBJECT (player
), "stream-song", &song
, NULL
);
1961 rb_shell_hidden_notify (shell
, 4000, song
, NULL
, NULL
);
1967 rb_shell_set_elapsed (RBShell
*shell
,
1971 char *elapsed_string
;
1974 rb_shell_player_get_playing (shell
->priv
->player_shell
, &playing
, NULL
);
1975 elapsed_string
= rb_shell_player_get_playing_time_string (shell
->priv
->player_shell
);
1977 if (shell
->priv
->cached_title
== NULL
)
1978 tooltip
= g_strdup (_("Not playing"));
1979 else if (!playing
) {
1980 /* Translators: the first %s is substituted by the song name, the second one is the elapsed and total time */
1981 tooltip
= g_strdup_printf (_("%s\nPaused, %s"),
1982 shell
->priv
->cached_title
, elapsed_string
);
1984 /* Translators: the first %s is substituted by the song name, the second one is the elapsed and total time */
1985 tooltip
= g_strdup_printf (_("%s\n%s"),
1986 shell
->priv
->cached_title
, elapsed_string
);
1989 rb_tray_icon_set_tooltip (shell
->priv
->tray_icon
, tooltip
);
1990 g_free (elapsed_string
);
1995 rb_shell_set_window_title (RBShell
*shell
,
1996 const char *window_title
)
1998 if (window_title
== NULL
) {
1999 rb_debug ("clearing title");
2001 g_free (shell
->priv
->cached_title
);
2002 shell
->priv
->cached_title
= NULL
;
2004 gtk_window_set_title (GTK_WINDOW (shell
->priv
->window
),
2011 rb_shell_player_get_playing (shell
->priv
->player_shell
, &playing
, NULL
);
2013 if (shell
->priv
->cached_title
&&
2014 !strcmp (shell
->priv
->cached_title
, window_title
) &&
2015 playing
== shell
->priv
->cached_playing
) {
2018 g_free (shell
->priv
->cached_title
);
2019 shell
->priv
->cached_title
= g_strdup (window_title
);
2020 shell
->priv
->cached_playing
= playing
;
2022 rb_debug ("setting title to \"%s\"", window_title
);
2024 /* Translators: %s is the song name */
2025 title
= g_strdup_printf (_("%s (Paused)"), window_title
);
2026 gtk_window_set_title (GTK_WINDOW (shell
->priv
->window
),
2030 gtk_window_set_title (GTK_WINDOW (shell
->priv
->window
),
2037 rb_shell_view_sourcelist_changed_cb (GtkAction
*action
,
2040 eel_gconf_set_boolean (CONF_UI_SOURCELIST_HIDDEN
,
2041 !gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action
)));
2045 rb_shell_view_toolbar_changed_cb (GtkAction
*action
,
2048 eel_gconf_set_boolean (CONF_UI_TOOLBAR_HIDDEN
,
2049 !gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action
)));
2053 rb_shell_view_smalldisplay_changed_cb (GtkAction
*action
,
2058 /* don't change more than once per second, it causes weirdness */
2059 g_get_current_time (&time
);
2060 if (time
.tv_sec
== shell
->priv
->last_small_time
)
2063 shell
->priv
->last_small_time
= time
.tv_sec
;
2065 shell
->priv
->window_small
= gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action
));
2066 eel_gconf_set_boolean (CONF_UI_SMALL_DISPLAY
, shell
->priv
->window_small
);
2070 rb_shell_view_statusbar_changed_cb (GtkAction
*action
,
2073 shell
->priv
->statusbar_hidden
= !gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action
));
2074 eel_gconf_set_boolean (CONF_UI_STATUSBAR_HIDDEN
, shell
->priv
->statusbar_hidden
);
2076 rb_shell_sync_statusbar_visibility (shell
);
2080 rb_shell_view_queue_as_sidebar_changed_cb (GtkAction
*action
,
2083 shell
->priv
->queue_as_sidebar
= gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action
));
2084 eel_gconf_set_boolean (CONF_UI_QUEUE_AS_SIDEBAR
, shell
->priv
->queue_as_sidebar
);
2086 if (shell
->priv
->queue_as_sidebar
&&
2087 shell
->priv
->selected_source
== RB_SOURCE (shell
->priv
->queue_source
)) {
2088 /* queue no longer exists as a source, so change to the library */
2089 rb_shell_select_source (shell
, RB_SOURCE (shell
->priv
->library_source
));
2092 rb_shell_playing_from_queue_cb (shell
->priv
->player_shell
, NULL
, shell
);
2094 rb_shell_sync_pane_visibility (shell
);
2098 rb_shell_view_party_mode_changed_cb (GtkAction
*action
,
2101 shell
->priv
->party_mode
= gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action
));
2102 rb_shell_sync_party_mode (shell
);
2106 rb_shell_cmd_about (GtkAction
*action
,
2111 GdkPixbuf
*pixbuf
= NULL
;
2113 const char *authors
[] = {
2115 #include "MAINTAINERS.tab"
2118 #include "MAINTAINERS.old.tab"
2121 #include "AUTHORS.tab"
2125 const char *documenters
[] = {
2126 #include "DOCUMENTERS.tab"
2130 const char *translator_credits
= _("translator_credits");
2132 const char *license
[] = {
2133 N_("Rhythmbox is free software; you can redistribute it and/or modify\n"
2134 "it under the terms of the GNU General Public License as published by\n"
2135 "the Free Software Foundation; either version 2 of the License, or\n"
2136 "(at your option) any later version.\n"),
2137 N_("Rhythmbox is distributed in the hope that it will be useful,\n"
2138 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
2139 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
2140 "GNU General Public License for more details.\n"),
2141 N_("You should have received a copy of the GNU General Public License\n"
2142 "along with Rhythmbox; if not, write to the Free Software Foundation, Inc.,\n"
2143 "51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n")
2146 char *license_trans
;
2148 pixbuf
= gdk_pixbuf_new_from_file (rb_file ("about-logo.png"), NULL
);
2150 authors
[0] = _("Maintainers:");
2151 for (tem
= authors
; *tem
!= NULL
; tem
++)
2153 *tem
= _("Former Maintainers:");
2154 for (; *tem
!= NULL
; tem
++)
2156 *tem
= _("Contributors:");
2158 comment
= g_string_new (_("Music management and playback software for GNOME."));
2160 license_trans
= g_strconcat (_(license
[0]), "\n", _(license
[1]), "\n",
2161 _(license
[2]), "\n", NULL
);
2163 gtk_show_about_dialog (GTK_WINDOW (shell
->priv
->window
),
2164 "name", "Rhythmbox",
2166 "copyright", "Copyright \xc2\xa9 2005 The Rhythmbox authors\nCopyright \xc2\xa9 2003 - 2005 Colin Walters\nCopyright \xc2\xa9 2002, 2003 Jorn Baayen",
2167 "license", license_trans
,
2168 "website", "http://www.gnome.org/projects/rhythmbox",
2169 "comments", comment
->str
,
2170 "authors", (const char **) authors
,
2171 "documenters", (const char **) documenters
,
2172 "translator-credits", strcmp (translator_credits
, "translator_credits") != 0 ? translator_credits
: NULL
,
2176 g_object_unref (pixbuf
);
2177 g_string_free (comment
, TRUE
);
2178 g_free (license_trans
);
2182 rb_shell_toggle_visibility (RBShell
*shell
)
2186 visible
= rb_shell_get_visibility (shell
);
2188 rb_shell_set_visibility (shell
, !visible
, FALSE
);
2192 rb_shell_cmd_toggle_visibility (GtkAction
*action
,
2195 rb_shell_toggle_visibility (shell
);
2199 rb_shell_cmd_quit (GtkAction
*action
,
2202 rb_shell_quit (shell
);
2206 rb_shell_cmd_contents (GtkAction
*action
,
2209 GError
*error
= NULL
;
2211 gnome_help_display ("rhythmbox.xml", NULL
, &error
);
2213 if (error
!= NULL
) {
2214 rb_error_dialog (NULL
, _("Couldn't display help"),
2215 "%s", error
->message
);
2216 g_error_free (error
);
2221 rb_shell_cmd_preferences (GtkAction
*action
,
2224 if (shell
->priv
->prefs
== NULL
) {
2225 shell
->priv
->prefs
= rb_shell_preferences_new (shell
->priv
->sources
);
2227 gtk_window_set_transient_for (GTK_WINDOW (shell
->priv
->prefs
),
2228 GTK_WINDOW (shell
->priv
->window
));
2229 gtk_widget_show_all (shell
->priv
->prefs
);
2232 gtk_window_present (GTK_WINDOW (shell
->priv
->prefs
));
2236 rb_shell_plugins_window_delete_cb (GtkWidget
*window
,
2240 gtk_widget_hide (window
);
2246 rb_shell_plugins_response_cb (GtkDialog
*dialog
,
2250 if (response_id
== GTK_RESPONSE_CLOSE
)
2251 gtk_widget_hide (GTK_WIDGET (dialog
));
2256 rb_shell_cmd_plugins (GtkAction
*action
,
2259 if (shell
->priv
->plugins
== NULL
) {
2262 shell
->priv
->plugins
= gtk_dialog_new_with_buttons (_("Configure Plugins"),
2263 GTK_WINDOW (shell
->priv
->window
),
2264 GTK_DIALOG_DESTROY_WITH_PARENT
,
2268 g_signal_connect_object (G_OBJECT (shell
->priv
->plugins
),
2270 G_CALLBACK (rb_shell_plugins_window_delete_cb
),
2272 g_signal_connect_object (G_OBJECT (shell
->priv
->plugins
),
2274 G_CALLBACK (rb_shell_plugins_response_cb
),
2277 manager
= rb_plugin_manager_new ();
2278 gtk_widget_show_all (GTK_WIDGET (manager
));
2279 gtk_container_add (GTK_CONTAINER (GTK_DIALOG (shell
->priv
->plugins
)->vbox
),
2283 gtk_window_present (GTK_WINDOW (shell
->priv
->plugins
));
2287 add_to_library_response_cb (GtkDialog
*dialog
,
2292 char *current_dir
= NULL
;
2293 GSList
*uri_list
= NULL
, *uris
= NULL
;
2295 if (response_id
!= GTK_RESPONSE_ACCEPT
) {
2296 gtk_widget_destroy (GTK_WIDGET (dialog
));
2300 current_dir
= gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dialog
));
2301 eel_gconf_set_string (CONF_STATE_ADD_DIR
, current_dir
);
2303 uri_list
= gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog
));
2304 if (uri_list
== NULL
) {
2305 uri_list
= g_slist_prepend (uri_list
, g_strdup (current_dir
));
2308 for (uris
= uri_list
; uris
; uris
= uris
->next
) {
2309 rb_shell_load_uri (shell
, (char *)uris
->data
, FALSE
, NULL
);
2310 g_free (uris
->data
);
2312 g_slist_free (uri_list
);
2313 g_free (current_dir
);
2314 gtk_widget_destroy (GTK_WIDGET (dialog
));
2316 if (shell
->priv
->save_db_id
> 0) {
2317 g_source_remove (shell
->priv
->save_db_id
);
2319 shell
->priv
->save_db_id
= g_timeout_add (10000, (GSourceFunc
) idle_save_rhythmdb
, shell
);
2323 rb_shell_cmd_add_folder_to_library (GtkAction
*action
,
2326 char * dir
= eel_gconf_get_string (CONF_STATE_ADD_DIR
);
2329 dialog
= rb_file_chooser_new (_("Import Folder into Library"),
2330 GTK_WINDOW (shell
->priv
->window
),
2331 GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER
,
2334 gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (dialog
),
2338 g_signal_connect_object (G_OBJECT (dialog
),
2340 G_CALLBACK (add_to_library_response_cb
),
2345 rb_shell_cmd_add_file_to_library (GtkAction
*action
,
2348 char * dir
= eel_gconf_get_string (CONF_STATE_ADD_DIR
);
2351 dialog
= rb_file_chooser_new (_("Import File into Library"),
2352 GTK_WINDOW (shell
->priv
->window
),
2353 GTK_FILE_CHOOSER_ACTION_OPEN
,
2356 gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (dialog
),
2360 g_signal_connect_object (G_OBJECT (dialog
),
2362 G_CALLBACK (add_to_library_response_cb
),
2367 rb_shell_cmd_extract_cd (GtkAction
*action
,
2370 GError
*error
= NULL
;
2372 if (g_find_program_in_path ("sound-juicer") == NULL
) {
2373 rb_error_dialog (GTK_WINDOW (shell
->priv
->window
),
2374 _("CD Ripper not found"),
2375 _("To extract CDs you must install the Sound Juicer CD Ripper package."));
2379 g_spawn_command_line_async ("sound-juicer", &error
);
2382 rb_error_dialog (GTK_WINDOW (shell
->priv
->window
),
2383 _("Couldn't run CD Ripper"),
2384 _("An error occurred while running sound-juicer: %s"),
2387 g_clear_error (&error
);
2391 rb_shell_quit (RBShell
*shell
)
2393 rb_debug ("Quitting");
2395 rb_plugins_engine_shutdown ();
2397 rb_podcast_source_shutdown (shell
->priv
->podcast_source
);
2399 #ifdef WITH_DAAP_SUPPORT
2400 rb_daap_sources_shutdown (shell
);
2401 rb_daap_sharing_shutdown (shell
);
2402 #endif /* WITH_DAAP_SUPPORT */
2403 rb_shell_shutdown (shell
);
2404 rb_shell_sync_state (shell
);
2405 g_object_unref (G_OBJECT (shell
));
2407 g_timeout_add (10000, (GSourceFunc
)gtk_main_quit
, NULL
);
2411 idle_handle_load_complete (RBShell
*shell
)
2413 GDK_THREADS_ENTER ();
2415 rb_debug ("load complete");
2417 rb_playlist_manager_load_playlists (shell
->priv
->playlist_manager
);
2418 shell
->priv
->load_complete
= TRUE
;
2419 shell
->priv
->save_playlist_id
= g_timeout_add (10000, (GSourceFunc
) idle_save_playlist_manager
, shell
->priv
->playlist_manager
);
2421 rhythmdb_start_action_thread (shell
->priv
->db
);
2423 GDK_THREADS_LEAVE ();
2429 rb_shell_load_complete_cb (RhythmDB
*db
,
2432 g_idle_add ((GSourceFunc
) idle_handle_load_complete
, shell
);
2436 rb_shell_sync_sourcelist_visibility (RBShell
*shell
)
2441 visible
= !eel_gconf_get_boolean (CONF_UI_SOURCELIST_HIDDEN
);
2444 gtk_widget_show (GTK_WIDGET (shell
->priv
->sourcelist
));
2446 gtk_widget_hide (GTK_WIDGET (shell
->priv
->sourcelist
));
2448 action
= gtk_action_group_get_action (shell
->priv
->actiongroup
,
2450 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action
),
2455 rb_shell_sync_pane_visibility (RBShell
*shell
)
2457 gboolean sourcelist_visible
;
2460 g_object_get (G_OBJECT (shell
->priv
->sourcelist
), "visible", &sourcelist_visible
, NULL
);
2461 if (shell
->priv
->queue_source
)
2462 g_object_set (G_OBJECT (shell
->priv
->queue_source
), "visibility", !shell
->priv
->queue_as_sidebar
, NULL
);
2464 if (shell
->priv
->queue_as_sidebar
)
2465 gtk_widget_show (shell
->priv
->queue_sidebar
);
2467 gtk_widget_hide (shell
->priv
->queue_sidebar
);
2469 if (sourcelist_visible
== FALSE
&& shell
->priv
->queue_as_sidebar
== FALSE
)
2470 gtk_widget_hide (GTK_WIDGET (shell
->priv
->queue_paned
));
2472 gtk_widget_show (GTK_WIDGET (shell
->priv
->queue_paned
));
2474 action
= gtk_action_group_get_action (shell
->priv
->actiongroup
,
2475 "ViewQueueAsSidebar");
2476 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action
),
2477 shell
->priv
->queue_as_sidebar
);
2482 rb_shell_sync_toolbar_state (RBShell
*shell
)
2487 guint toolbar_style
;
2489 visible
= !eel_gconf_get_boolean (CONF_UI_TOOLBAR_HIDDEN
);
2491 toolbar
= gtk_ui_manager_get_widget (shell
->priv
->ui_manager
, "/ToolBar");
2493 gtk_widget_show (toolbar
);
2495 gtk_widget_hide (toolbar
);
2497 action
= gtk_action_group_get_action (shell
->priv
->actiongroup
,
2499 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action
),
2502 /* icons-only in small mode */
2503 if (shell
->priv
->window_small
)
2506 toolbar_style
= eel_gconf_get_integer (CONF_UI_TOOLBAR_STYLE
);
2508 switch (toolbar_style
) {
2511 gtk_toolbar_unset_style (GTK_TOOLBAR (toolbar
));
2514 /* text below icons */
2515 gtk_toolbar_set_style (GTK_TOOLBAR (toolbar
), GTK_TOOLBAR_BOTH
);
2518 /* text beside icons */
2519 gtk_toolbar_set_style (GTK_TOOLBAR (toolbar
), GTK_TOOLBAR_BOTH_HORIZ
);
2523 gtk_toolbar_set_style (GTK_TOOLBAR (toolbar
), GTK_TOOLBAR_ICONS
);
2527 gtk_toolbar_set_style (GTK_TOOLBAR (toolbar
), GTK_TOOLBAR_TEXT
);
2530 g_warning ("unknown toolbar style type");
2531 gtk_toolbar_unset_style (GTK_TOOLBAR (toolbar
));
2536 window_state_event_cb (GtkWidget
*widget
,
2537 GdkEventWindowState
*event
,
2540 if (event
->changed_mask
& GDK_WINDOW_STATE_ICONIFIED
) {
2541 rb_shell_present (shell
, gtk_get_current_event_time (), NULL
);
2548 rb_shell_sync_party_mode (RBShell
*shell
)
2552 /* party mode does not use gconf as a model since it
2553 should not be persistent */
2555 /* disable/enable quit action */
2556 action
= gtk_action_group_get_action (shell
->priv
->actiongroup
, "MusicClose");
2557 g_object_set (G_OBJECT (action
), "sensitive", !shell
->priv
->party_mode
, NULL
);
2558 action
= gtk_action_group_get_action (shell
->priv
->actiongroup
, "MusicQuit");
2559 g_object_set (G_OBJECT (action
), "sensitive", !shell
->priv
->party_mode
, NULL
);
2560 action
= gtk_action_group_get_action (shell
->priv
->actiongroup
, "ViewSmallDisplay");
2561 g_object_set (G_OBJECT (action
), "sensitive", !shell
->priv
->party_mode
, NULL
);
2563 /* show/hide queue as sidebar ? */
2565 g_object_set (shell
->priv
->player_shell
, "queue-only", shell
->priv
->party_mode
, NULL
);
2567 /* Set playlist manager source to the current source to update properties */
2568 if (shell
->priv
->selected_source
) {
2569 g_object_set (G_OBJECT (shell
->priv
->playlist_manager
), "source", shell
->priv
->selected_source
, NULL
);
2570 rb_shell_clipboard_set_source (shell
->priv
->clipboard_shell
, shell
->priv
->selected_source
);
2573 gtk_window_set_keep_above (GTK_WINDOW (shell
->priv
->window
), shell
->priv
->party_mode
);
2574 if (shell
->priv
->party_mode
) {
2575 gtk_window_fullscreen (GTK_WINDOW (shell
->priv
->window
));
2576 gtk_window_stick (GTK_WINDOW (shell
->priv
->window
));
2577 g_signal_connect (shell
->priv
->window
, "window-state-event", G_CALLBACK (window_state_event_cb
), shell
);
2579 gtk_window_unstick (GTK_WINDOW (shell
->priv
->window
));
2580 gtk_window_unfullscreen (GTK_WINDOW (shell
->priv
->window
));
2581 g_signal_handlers_disconnect_by_func (shell
->priv
->window
, window_state_event_cb
, shell
);
2586 rb_shell_sync_smalldisplay (RBShell
*shell
)
2589 GtkAction
*queue_action
;
2590 GtkAction
*party_mode_action
;
2593 rb_shell_sync_window_state (shell
, FALSE
);
2595 action
= gtk_action_group_get_action (shell
->priv
->actiongroup
,
2597 queue_action
= gtk_action_group_get_action (shell
->priv
->actiongroup
,
2598 "ViewQueueAsSidebar");
2599 party_mode_action
= gtk_action_group_get_action (shell
->priv
->actiongroup
,
2602 toolbar
= gtk_ui_manager_get_widget (shell
->priv
->ui_manager
, "/ToolBar");
2604 if (shell
->priv
->window_small
) {
2605 g_object_set (G_OBJECT (action
), "sensitive", FALSE
, NULL
);
2606 g_object_set (G_OBJECT (queue_action
), "sensitive", FALSE
, NULL
);
2607 g_object_set (G_OBJECT (party_mode_action
), "sensitive", FALSE
, NULL
);
2609 gtk_widget_hide (GTK_WIDGET (shell
->priv
->paned
));
2611 g_object_set (G_OBJECT (action
), "sensitive", TRUE
, NULL
);
2612 g_object_set (G_OBJECT (queue_action
), "sensitive", TRUE
, NULL
);
2613 g_object_set (G_OBJECT (party_mode_action
), "sensitive", TRUE
, NULL
);
2615 gtk_widget_show (GTK_WIDGET (shell
->priv
->paned
));
2617 rb_shell_sync_statusbar_visibility (shell
);
2618 rb_shell_sync_toolbar_state (shell
);
2620 rb_source_header_sync_control_state (shell
->priv
->source_header
);
2622 action
= gtk_action_group_get_action (shell
->priv
->actiongroup
,
2623 "ViewSmallDisplay");
2624 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action
),
2625 shell
->priv
->window_small
);
2629 rb_shell_sync_statusbar_visibility (RBShell
*shell
)
2631 if (shell
->priv
->statusbar_hidden
|| shell
->priv
->window_small
)
2632 gtk_widget_hide (GTK_WIDGET (shell
->priv
->statusbar
));
2634 gtk_widget_show (GTK_WIDGET (shell
->priv
->statusbar
));
2638 sourcelist_visibility_changed_cb (GConfClient
*client
,
2643 rb_debug ("sourcelist visibility changed");
2644 rb_shell_sync_sourcelist_visibility (shell
);
2645 rb_shell_sync_pane_visibility (shell
);
2649 toolbar_state_changed_cb (GConfClient
*client
,
2654 rb_debug ("toolbar state changed");
2655 rb_shell_sync_toolbar_state (shell
);
2659 smalldisplay_changed_cb (GConfClient
*client
,
2664 rb_debug ("small display mode changed");
2665 shell
->priv
->window_small
= eel_gconf_get_boolean (CONF_UI_SMALL_DISPLAY
);
2666 rb_shell_sync_smalldisplay (shell
);
2670 rb_shell_sync_paned (RBShell
*shell
)
2672 gtk_paned_set_position (GTK_PANED (shell
->priv
->paned
),
2673 shell
->priv
->paned_position
);
2674 gtk_paned_set_position (GTK_PANED (shell
->priv
->queue_paned
),
2675 shell
->priv
->sourcelist_height
);
2679 paned_size_allocate_cb (GtkWidget
*widget
,
2680 GtkAllocation
*allocation
,
2683 shell
->priv
->paned_position
= gtk_paned_get_position (GTK_PANED (shell
->priv
->paned
));
2684 rb_debug ("paned position %d", shell
->priv
->paned_position
);
2685 eel_gconf_set_integer (CONF_STATE_PANED_POSITION
, shell
->priv
->paned_position
);
2689 sidebar_paned_size_allocate_cb (GtkWidget
*widget
,
2690 GtkAllocation
*allocation
,
2693 shell
->priv
->sourcelist_height
= gtk_paned_get_position (GTK_PANED (shell
->priv
->queue_paned
));
2694 rb_debug ("sidebar paned position %d", shell
->priv
->sourcelist_height
);
2695 eel_gconf_set_integer (CONF_STATE_SOURCELIST_HEIGHT
, shell
->priv
->sourcelist_height
);
2699 sourcelist_drag_received_cb (RBSourceList
*sourcelist
,
2701 GtkSelectionData
*data
,
2704 if (source
== NULL
) {
2705 source
= rb_playlist_manager_new_playlist_from_selection_data (shell
->priv
->playlist_manager
,
2709 if (source
!= NULL
) {
2710 rb_source_receive_drag (source
, data
);
2716 rb_shell_cmd_current_song (GtkAction
*action
,
2719 rb_debug ("current song");
2721 rb_shell_jump_to_current (shell
);
2726 rb_shell_cmd_view_all (GtkAction
*action
,
2729 rb_debug ("view all");
2731 rb_source_reset_filters (shell
->priv
->selected_source
);
2732 rb_source_header_clear_search (shell
->priv
->source_header
);
2733 rb_source_header_focus_search_box (shell
->priv
->source_header
);
2737 rb_shell_jump_to_entry_with_source (RBShell
*shell
,
2739 RhythmDBEntry
*entry
)
2743 g_return_if_fail (entry
!= NULL
);
2745 if ((source
== RB_SOURCE (shell
->priv
->queue_source
) &&
2746 shell
->priv
->queue_as_sidebar
) ||
2748 RhythmDBEntryType entry_type
;
2749 entry_type
= rhythmdb_entry_get_entry_type (entry
);
2750 source
= rb_shell_get_source_by_entry_type (shell
, entry_type
);
2755 songs
= rb_source_get_entry_view (source
);
2756 rb_shell_select_source (shell
, source
);
2758 rb_entry_view_scroll_to_entry (songs
, entry
);
2759 rb_entry_view_select_entry (songs
, entry
);
2763 rb_shell_play_entry (RBShell
*shell
,
2764 RhythmDBEntry
*entry
)
2766 rb_shell_player_stop (shell
->priv
->player_shell
);
2767 rb_shell_jump_to_entry_with_source (shell
, NULL
, entry
);
2768 rb_shell_player_play_entry (shell
->priv
->player_shell
, entry
);
2772 rb_shell_jump_to_current (RBShell
*shell
)
2774 RBSource
*source
= rb_shell_player_get_playing_source (shell
->priv
->player_shell
);
2775 RhythmDBEntry
*playing
;
2777 g_return_if_fail (source
!= NULL
);
2779 playing
= rb_shell_player_get_playing_entry (shell
->priv
->player_shell
);
2781 rb_shell_jump_to_entry_with_source (shell
, source
, playing
);
2785 rb_shell_show_popup_cb (RBSourceList
*sourcelist
,
2790 return rb_source_show_popup (target
);
2794 tray_embedded_cb (GtkPlug
*plug
,
2797 /* FIXME - this doens't work */
2799 RBShell
*shell
= RB_SHELL (data
);
2801 rb_debug ("got embedded signal");
2803 gdk_window_set_decorations (shell
->priv
->window
->window
,
2804 GDK_DECOR_ALL
| GDK_DECOR_MINIMIZE
| GDK_DECOR_MAXIMIZE
);
2809 tray_destroy_cb (GtkObject
*object
,
2812 if (shell
->priv
->tray_icon
) {
2813 rb_debug ("caught destroy event for tray icon %p", object
);
2814 gtk_object_sink (object
);
2815 shell
->priv
->tray_icon
= NULL
;
2816 rb_debug ("finished sinking tray");
2819 rb_debug ("creating new tray icon");
2820 shell
->priv
->tray_icon
= rb_tray_icon_new (shell
->priv
->ui_manager
, shell
);
2821 g_signal_connect_object (G_OBJECT (shell
->priv
->tray_icon
), "destroy",
2822 G_CALLBACK (tray_destroy_cb
), shell
, 0);
2823 g_signal_connect_object (G_OBJECT (shell
->priv
->tray_icon
), "embedded",
2824 G_CALLBACK (tray_embedded_cb
), shell
, 0);
2826 gtk_widget_show_all (GTK_WIDGET (shell
->priv
->tray_icon
));
2828 rb_debug ("done creating new tray icon %p", shell
->priv
->tray_icon
);
2833 rb_shell_hidden_notify (RBShell
*shell
,
2835 const char *primary
,
2837 const char *secondary
)
2840 if (rb_shell_get_visibility (shell
)) {
2841 rb_debug ("shell is visible, not notifying");
2845 rb_tray_icon_notify (shell
->priv
->tray_icon
,
2851 session_die_cb (GnomeClient
*client
,
2854 rb_debug ("session die");
2855 rb_shell_quit (shell
);
2859 rb_shell_error_quark (void)
2861 static GQuark quark
= 0;
2863 quark
= g_quark_from_static_string ("rb_shell_error");
2869 save_yourself_cb (GnomeClient
*client
,
2871 GnomeSaveStyle save_style
,
2873 GnomeInteractStyle interact_style
,
2877 rb_debug ("session save yourself");
2878 rb_shell_sync_state (shell
);
2883 rb_shell_session_init (RBShell
*shell
)
2885 GnomeClient
*client
;
2887 client
= gnome_master_client ();
2889 g_signal_connect_object (G_OBJECT (client
),
2891 G_CALLBACK (save_yourself_cb
),
2894 g_signal_connect_object (G_OBJECT (client
),
2896 G_CALLBACK (session_die_cb
),
2901 rb_shell_guess_type_for_uri (RBShell
*shell
,
2904 GnomeVFSURI
*vfs_uri
;
2905 RhythmDBEntryType entry_type
= RHYTHMDB_ENTRY_TYPE_SONG
;
2908 const char *pathend
;
2911 return RHYTHMDB_ENTRY_TYPE_INVALID
;
2913 vfs_uri
= gnome_vfs_uri_new (uri
);
2914 if (vfs_uri
== NULL
) {
2915 rb_debug ("Invalid uri: %s", uri
);
2916 return RHYTHMDB_ENTRY_TYPE_INVALID
;
2918 scheme
= gnome_vfs_uri_get_scheme (vfs_uri
);
2919 path
= gnome_vfs_uri_get_scheme (vfs_uri
);
2920 pathend
= path
+ strlen (path
);
2922 if (strcmp ("file", scheme
) == 0) {
2923 entry_type
= RHYTHMDB_ENTRY_TYPE_SONG
;
2924 } else if (strcmp ("http", scheme
) == 0) {
2925 if ((strcasecmp (".xml", pathend
-4) == 0)
2926 || strcasecmp (".rss", pathend
-4) == 0)
2927 entry_type
= RHYTHMDB_ENTRY_TYPE_PODCAST_FEED
;
2929 entry_type
= RHYTHMDB_ENTRY_TYPE_IRADIO_STATION
;
2930 } else if ((strcmp ("pnm", scheme
) == 0) ||
2931 (strcmp ("rtsp", scheme
) == 0) ||
2932 (strcmp ("mms", scheme
) == 0) ||
2933 (strcmp ("mmsh", scheme
) == 0)) {
2934 entry_type
= RHYTHMDB_ENTRY_TYPE_IRADIO_STATION
;
2937 gnome_vfs_uri_unref (vfs_uri
);
2941 /* Load a URI representing an element of the given type, with
2945 rb_shell_add_uri (RBShell
*shell
,
2946 RhythmDBEntryType entrytype
,
2954 /* FIXME should abstract this... */
2955 source
= rb_shell_get_source_by_entry_type (shell
, entrytype
);
2956 if (source
== RB_SOURCE (shell
->priv
->iradio_source
)) {
2957 if (rb_uri_is_local (uri
)) {
2958 rb_iradio_source_add_from_playlist (shell
->priv
->iradio_source
,
2961 rb_iradio_source_add_station (shell
->priv
->iradio_source
,
2967 } else if (source
== RB_SOURCE (shell
->priv
->podcast_source
)) {
2968 rb_podcast_source_add_feed (shell
->priv
->podcast_source
, uri
);
2970 } else if (entrytype
== RHYTHMDB_ENTRY_TYPE_SONG
) {
2971 /* FIXME should be sync... */
2972 rhythmdb_add_uri (shell
->priv
->db
, uri
);
2975 g_assert_not_reached ();
2982 gboolean iradio_playlist
;
2983 } PlaylistParseData
;
2986 handle_playlist_entry_cb (TotemPlParser
*playlist
,
2990 PlaylistParseData
*data
)
2992 RhythmDBEntryType entry_type
;
2994 g_return_if_fail (uri
!= NULL
);
2996 entry_type
= rb_shell_guess_type_for_uri (data
->shell
, uri
);
2998 if (entry_type
!= RHYTHMDB_ENTRY_TYPE_IRADIO_STATION
)
2999 data
->iradio_playlist
= FALSE
;
3002 /* Load a URI representing a single song, a directory, a playlist, or
3003 * an internet radio station, and optionally start playing it.
3005 * For playlists containing only stream URLs, we either add the playlist
3006 * itself (if it's remote) or each URL from it (if it's local). The main
3007 * reason for this is so clicking on stream playlist links in web browsers
3008 * works properly - the playlist file will be downloaded to /tmp/, and
3009 * we can't add that to the database, so we need to add the stream URLs
3013 rb_shell_load_uri (RBShell
*shell
,
3018 RhythmDBEntry
*entry
;
3020 entry
= rhythmdb_entry_lookup_by_location (shell
->priv
->db
, uri
);
3022 if (entry
== NULL
) {
3023 TotemPlParser
*parser
;
3024 TotemPlParserResult result
;
3025 PlaylistParseData data
;
3028 if (rb_uri_is_local (uri
)) {
3029 /* TODO: we'd need to grab the first stream URL from the playlist
3030 * to be able to play stations added this way.
3035 rb_debug ("adding uri %s", uri
);
3036 parser
= totem_pl_parser_new ();
3038 g_signal_connect_data (G_OBJECT (parser
), "entry",
3039 G_CALLBACK (handle_playlist_entry_cb
),
3042 totem_pl_parser_add_ignored_mimetype (parser
, "x-directory/normal");
3043 if (g_object_class_find_property (G_OBJECT_GET_CLASS (parser
), "recurse"))
3044 g_object_set (G_OBJECT (parser
), "recurse", FALSE
, NULL
);
3046 result
= totem_pl_parser_parse (parser
, uri
, FALSE
);
3047 g_object_unref (parser
);
3049 if (result
== TOTEM_PL_PARSER_RESULT_SUCCESS
&& data
.iradio_playlist
== FALSE
) {
3050 rb_debug ("adding %s as a static playlist", uri
);
3051 if (!rb_playlist_manager_parse_file (shell
->priv
->playlist_manager
,
3055 RhythmDBEntryType entrytype
;
3057 if (result
== TOTEM_PL_PARSER_RESULT_SUCCESS
) {
3058 rb_debug ("adding %s as an iradio playlist", uri
);
3059 entrytype
= RHYTHMDB_ENTRY_TYPE_IRADIO_STATION
;
3061 rb_debug ("%s didn't parse as a playlist", uri
);
3062 entrytype
= rb_shell_guess_type_for_uri (shell
, uri
);
3067 rb_shell_add_uri (shell
, entrytype
, uri
, NULL
, NULL
, NULL
);
3073 entry
= rhythmdb_entry_lookup_by_location (shell
->priv
->db
, uri
);
3076 rb_shell_play_entry (shell
, entry
);
3078 /* wait for the entry to be added, and then play it */
3079 if (shell
->priv
->pending_entry
)
3080 g_free (shell
->priv
->pending_entry
);
3082 shell
->priv
->pending_entry
= g_strdup (uri
);
3090 rb_shell_get_party_mode (RBShell
*shell
)
3092 return shell
->priv
->party_mode
;
3096 rb_shell_get_player (RBShell
*shell
)
3098 return G_OBJECT (shell
->priv
->player_shell
);
3102 rb_shell_get_player_path (RBShell
*shell
)
3104 return "/org/gnome/Rhythmbox/Player";
3108 rb_shell_get_playlist_manager (RBShell
*shell
)
3110 return G_OBJECT (shell
->priv
->playlist_manager
);
3114 rb_shell_get_playlist_manager_path (RBShell
*shell
)
3116 return "/org/gnome/Rhythmbox/PlaylistManager";
3120 rb_shell_get_ui_manager (RBShell
*shell
)
3122 return G_OBJECT (shell
->priv
->ui_manager
);
3126 rb_shell_add_to_queue (RBShell
*shell
,
3130 rb_static_playlist_source_add_location (RB_STATIC_PLAYLIST_SOURCE (shell
->priv
->queue_source
),
3136 rb_shell_remove_from_queue (RBShell
*shell
,
3140 if (rb_playlist_source_location_in_map (RB_PLAYLIST_SOURCE (shell
->priv
->queue_source
), uri
))
3141 rb_static_playlist_source_remove_location (RB_STATIC_PLAYLIST_SOURCE (shell
->priv
->queue_source
),
3148 rb_shell_present (RBShell
*shell
,
3152 rb_profile_start ("presenting shell");
3154 rb_debug ("presenting with timestamp %u", timestamp
);
3155 gtk_widget_show (GTK_WIDGET (shell
->priv
->window
));
3156 #if GTK_MINOR_VERSION >= 8
3157 gtk_window_present_with_time (GTK_WINDOW (shell
->priv
->window
), timestamp
);
3159 gtk_window_present (GTK_WINDOW (shell
->priv
->window
));
3160 gdk_window_focus (GTK_WIDGET (shell
->priv
->window
)->window
, timestamp
);
3163 rb_profile_end ("presenting shell");
3169 unset_and_free_g_value (gpointer valpointer
)
3171 GValue
*value
= valpointer
;
3172 g_value_unset (value
);
3177 rb_shell_get_song_properties (RBShell
*shell
,
3179 GHashTable
**properties
,
3182 RhythmDBEntry
*entry
;
3186 entry
= rhythmdb_entry_lookup_by_location (shell
->priv
->db
, uri
);
3188 if (entry
== NULL
) {
3191 RB_SHELL_ERROR_NO_SUCH_URI
,
3192 _("Unknown song URI: %s"),
3197 *properties
= g_hash_table_new_full (g_str_hash
, g_str_equal
,
3199 unset_and_free_g_value
);
3201 klass
= g_type_class_ref (RHYTHMDB_TYPE_PROP_TYPE
);
3202 for (i
= 0; i
< klass
->n_values
; i
++) {
3207 prop
= klass
->values
[i
].value
;
3209 /* only include easily marshallable types in the hash table */
3210 value_type
= rhythmdb_get_property_type (shell
->priv
->db
, prop
);
3211 switch (value_type
) {
3213 case G_TYPE_BOOLEAN
:
3222 value
= g_new0 (GValue
, 1);
3223 g_value_init (value
, value_type
);
3224 rhythmdb_entry_get (shell
->priv
->db
, entry
, prop
, value
);
3225 g_hash_table_insert (*properties
,
3226 (gpointer
) rhythmdb_nice_elt_name_from_propid (shell
->priv
->db
, prop
),
3229 g_type_class_unref (klass
);
3235 rb_shell_set_song_property (RBShell
*shell
,
3237 const char *propname
,
3238 const GValue
*value
,
3241 RhythmDBEntry
*entry
;
3245 entry
= rhythmdb_entry_lookup_by_location (shell
->priv
->db
, uri
);
3247 if (entry
== NULL
) {
3250 RB_SHELL_ERROR_NO_SUCH_URI
,
3251 _("Unknown song URI: %s"),
3256 if ((propid
= rhythmdb_propid_from_nice_elt_name (shell
->priv
->db
, (guchar
*) propname
)) < 0) {
3259 RB_SHELL_ERROR_NO_SUCH_PROPERTY
,
3260 _("Unknown property %s"),
3265 proptype
= rhythmdb_get_property_type (shell
->priv
->db
, propid
);
3266 if (G_VALUE_TYPE (value
) != proptype
) {
3269 RB_SHELL_ERROR_INVALID_PROPERTY_TYPE
,
3270 _("Invalid property type %s for property %s"),
3271 g_type_name (G_VALUE_TYPE (value
)),
3276 rhythmdb_entry_set (shell
->priv
->db
, entry
, propid
, value
);
3281 rb_shell_volume_widget_changed_cb (BaconVolumeButton
*vol
,
3284 if (!shell
->priv
->syncing_volume
)
3285 g_object_set (shell
->priv
->player_shell
,
3286 "volume", bacon_volume_button_get_value (vol
),
3291 rb_shell_player_volume_changed_cb (RBShellPlayer
*player
,
3296 g_object_get (G_OBJECT (player
), "volume", &volume
, NULL
);
3297 shell
->priv
->syncing_volume
= TRUE
;
3298 bacon_volume_button_set_value (BACON_VOLUME_BUTTON (shell
->priv
->volume_button
),
3300 shell
->priv
->syncing_volume
= FALSE
;
3305 rb_shell_druid_response_cb (GtkDialog
*druid
,
3309 gtk_widget_show_all (GTK_WIDGET (shell
->priv
->window
));
3310 gtk_widget_destroy (GTK_WIDGET (druid
));
3314 rb_shell_get_box_for_ui_location (RBShell
*shell
, RBShellUILocation location
)
3319 case RB_SHELL_UI_LOCATION_SIDEBAR
:
3320 box
= shell
->priv
->sidebar_container
;
3322 case RB_SHELL_UI_LOCATION_MAIN_TOP
:
3323 box
= shell
->priv
->top_container
;
3325 case RB_SHELL_UI_LOCATION_MAIN_BOTTOM
:
3326 box
= shell
->priv
->bottom_container
;
3334 rb_shell_add_widget (RBShell
*shell
, GtkWidget
*widget
, RBShellUILocation location
)
3338 box
= rb_shell_get_box_for_ui_location (shell
, location
);
3339 g_return_if_fail (box
!= NULL
);
3341 gtk_box_pack_start (box
, widget
, FALSE
, TRUE
, 0);
3345 rb_shell_remove_widget (RBShell
*shell
, GtkWidget
*widget
, RBShellUILocation location
)
3349 box
= rb_shell_get_box_for_ui_location (shell
, location
);
3350 g_return_if_fail (box
!= NULL
);
3352 gtk_container_remove (GTK_CONTAINER (box
), widget
);
3355 /* This should really be standard. */
3356 #define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
3359 rb_shell_ui_location_get_type (void)
3361 static GType etype
= 0;
3364 static const GEnumValue values
[] = {
3365 ENUM_ENTRY (RB_SHELL_UI_LOCATION_SIDEBAR
, "Sidebar"),
3366 ENUM_ENTRY (RB_SHELL_UI_LOCATION_MAIN_TOP
, "Main Top"),
3367 ENUM_ENTRY (RB_SHELL_UI_LOCATION_MAIN_BOTTOM
, "Main Bottom"),
3371 etype
= g_enum_register_static ("RBShellUILocation", values
);