hythmbox-2.98/shell/rb-shell-preferences.c

No issues found

  1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
  2  *
  3  *  Copyright (C) 2002 Jorn Baayen <jorn@nl.linux.org>
  4  *  Copyright (C) 2003 Colin Walters <walters@debian.org>
  5  *
  6  *  This program is free software; you can redistribute it and/or modify
  7  *  it under the terms of the GNU General Public License as published by
  8  *  the Free Software Foundation; either version 2 of the License, or
  9  *  (at your option) any later version.
 10  *
 11  *  The Rhythmbox authors hereby grant permission for non-GPL compatible
 12  *  GStreamer plugins to be used and distributed together with GStreamer
 13  *  and Rhythmbox. This permission is above and beyond the permissions granted
 14  *  by the GPL license by which Rhythmbox is covered. If you modify this code
 15  *  you may extend this exception to your version of the code, but you are not
 16  *  obligated to do so. If you do not wish to do so, delete this exception
 17  *  statement from your version.
 18  *
 19  *  This program is distributed in the hope that it will be useful,
 20  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 21  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 22  *  GNU General Public License for more details.
 23  *
 24  *  You should have received a copy of the GNU General Public License
 25  *  along with this program; if not, write to the Free Software
 26  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA.
 27  *
 28  */
 29 
 30 /**
 31  * SECTION:rb-shell-preferences
 32  * @short_description: preferences dialog
 33  *
 34  * The preferences dialog is built around a #GtkNotebook widget, with two built-in
 35  * pages and additional pages for various sources.
 36  *
 37  * The 'general' preferences page controls the set of browser views that are visible
 38  * (artist and album; genre and artist; or genre, artist, and album), the columns
 39  * that are visible, and the appearance of buttons in the main toolbar.  The browser
 40  * and column settings apply to all sources.
 41  *
 42  * The 'playback' preferences page controls whether the crossfading player backend is used,
 43  * and if enabled, the crossfade duration and network buffer size.
 44  *
 45  * Currently, the library and podcast sources add pages to the notebook, for configuring the
 46  * location and layout of the library and the podcast download location and update frequency.
 47  */
 48 
 49 #include <config.h>
 50 
 51 #include <string.h>
 52 
 53 #include <glib/gi18n.h>
 54 #include <gtk/gtk.h>
 55 
 56 #include "rb-file-helpers.h"
 57 #include "rb-shell-preferences.h"
 58 #include "rb-source.h"
 59 #include "rb-builder-helpers.h"
 60 #include "rb-dialog.h"
 61 #include "rb-debug.h"
 62 #include "rb-shell.h"
 63 #include "rb-util.h"
 64 
 65 static void rb_shell_preferences_class_init (RBShellPreferencesClass *klass);
 66 static void rb_shell_preferences_init (RBShellPreferences *shell_preferences);
 67 static void impl_finalize (GObject *object);
 68 static void impl_dispose (GObject *object);
 69 static gboolean rb_shell_preferences_window_delete_cb (GtkWidget *window,
 70 				                       GdkEventAny *event,
 71 				                       RBShellPreferences *shell_preferences);
 72 static void rb_shell_preferences_response_cb (GtkDialog *dialog,
 73 				              int response_id,
 74 				              RBShellPreferences *shell_preferences);
 75 
 76 void rb_shell_preferences_column_check_changed_cb (GtkCheckButton *butt,
 77 						   RBShellPreferences *shell_preferences);
 78 void rb_shell_preferences_browser_views_activated_cb (GtkWidget *widget,
 79 						      RBShellPreferences *shell_preferences);
 80 
 81 static void column_check_toggled_cb (GtkWidget *widget, RBShellPreferences *preferences);
 82 
 83 static void player_settings_changed_cb (GSettings *settings, const char *key, RBShellPreferences *preferences);
 84 static void source_settings_changed_cb (GSettings *settings, const char *key, RBShellPreferences *preferences);
 85 static void transition_time_changed_cb (GtkRange *range, RBShellPreferences *preferences);
 86 
 87 enum
 88 {
 89 	PROP_0,
 90 };
 91 
 92 #define COLUMN_CHECK_PROP_NAME	"rb-column-prop-name"
 93 
 94 struct {
 95 	const char *widget;
 96 	RhythmDBPropType prop;
 97 } column_checks[] = {
 98 	{ "track_check",	RHYTHMDB_PROP_TRACK_NUMBER },
 99 	{ "artist_check",	RHYTHMDB_PROP_ARTIST },
100 	{ "album_check",	RHYTHMDB_PROP_ALBUM },
101 	{ "year_check",		RHYTHMDB_PROP_DATE },
102 	{ "last_played_check",	RHYTHMDB_PROP_LAST_PLAYED },
103 	{ "genre_check",	RHYTHMDB_PROP_GENRE },
104 	{ "first_seen_check",	RHYTHMDB_PROP_FIRST_SEEN },
105 	{ "play_count_check",	RHYTHMDB_PROP_PLAY_COUNT },
106 	{ "comment_check",	RHYTHMDB_PROP_COMMENT },
107 	{ "bpm_check",		RHYTHMDB_PROP_BPM },
108 	{ "rating_check",	RHYTHMDB_PROP_RATING },
109 	{ "duration_check",	RHYTHMDB_PROP_DURATION },
110 	{ "location_check",	RHYTHMDB_PROP_LOCATION },
111 	{ "quality_check",	RHYTHMDB_PROP_BITRATE }
112 };
113 
114 
115 struct RBShellPreferencesPrivate
116 {
117 	GtkWidget *notebook;
118 
119 	GHashTable *column_checks;
120 	GtkWidget *general_prefs_plugin_box;
121 
122 	GtkWidget *xfade_backend_check;
123 	GtkWidget *transition_duration;
124 	GtkWidget *playback_prefs_plugin_box;
125 
126 	GSList *browser_views_group;
127 
128 	gboolean applying_settings;
129 
130 	GSettings *main_settings;
131 	GSettings *source_settings;
132 	GSettings *player_settings;
133 };
134 
135 
136 G_DEFINE_TYPE (RBShellPreferences, rb_shell_preferences, GTK_TYPE_DIALOG)
137 
138 static void
139 rb_shell_preferences_class_init (RBShellPreferencesClass *klass)
140 {
141 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
142 
143 	object_class->finalize = impl_finalize;
144 	object_class->dispose = impl_dispose;
145 
146 	g_type_class_add_private (klass, sizeof (RBShellPreferencesPrivate));
147 }
148 
149 static void
150 help_cb (GtkWidget *widget,
151 	 RBShellPreferences *shell_preferences)
152 {
153 	GError *error = NULL;
154 
155 	gtk_show_uri (gtk_widget_get_screen (widget),
156 		      "ghelp:rhythmbox?prefs",
157 		      gtk_get_current_event_time (),
158 		      &error);
159 
160 	if (error != NULL) {
161 		rb_error_dialog (NULL,
162 				 _("Couldn't display help"),
163 				 "%s", error->message);
164 
165 		g_error_free (error);
166 	}
167 }
168 
169 static void
170 rb_shell_preferences_init (RBShellPreferences *shell_preferences)
171 {
172 	GtkWidget *tmp;
173 	GtkWidget *content_area;
174 	GtkBuilder *builder;
175 	int i;
176 
177 	shell_preferences->priv = G_TYPE_INSTANCE_GET_PRIVATE (shell_preferences,
178 							       RB_TYPE_SHELL_PREFERENCES,
179 							       RBShellPreferencesPrivate);
180 
181 	g_signal_connect_object (shell_preferences,
182 				 "delete_event",
183 				 G_CALLBACK (rb_shell_preferences_window_delete_cb),
184 				 shell_preferences, 0);
185 	g_signal_connect_object (shell_preferences,
186 				 "response",
187 				 G_CALLBACK (rb_shell_preferences_response_cb),
188 				 shell_preferences, 0);
189 
190 	gtk_dialog_add_button (GTK_DIALOG (shell_preferences),
191 			       GTK_STOCK_CLOSE,
192 			       GTK_RESPONSE_CLOSE);
193 	tmp = gtk_dialog_add_button (GTK_DIALOG (shell_preferences),
194 			              GTK_STOCK_HELP,
195 			              GTK_RESPONSE_HELP);
196 	g_signal_connect_object (tmp, "clicked",
197 				 G_CALLBACK (help_cb), shell_preferences, 0);
198 	gtk_dialog_set_default_response (GTK_DIALOG (shell_preferences),
199 					 GTK_RESPONSE_CLOSE);
200 
201 	gtk_window_set_title (GTK_WINDOW (shell_preferences), _("Rhythmbox Preferences"));
202 	gtk_window_set_resizable (GTK_WINDOW (shell_preferences), FALSE);
203 
204 	shell_preferences->priv->notebook = GTK_WIDGET (gtk_notebook_new ());
205 	gtk_container_set_border_width (GTK_CONTAINER (shell_preferences->priv->notebook), 5);
206 
207 	content_area = gtk_dialog_get_content_area (GTK_DIALOG (shell_preferences));
208 	gtk_container_add (GTK_CONTAINER (content_area),
209 			   shell_preferences->priv->notebook);
210 
211 	gtk_container_set_border_width (GTK_CONTAINER (shell_preferences), 5);
212 	gtk_box_set_spacing (GTK_BOX (content_area), 2);
213 
214 	shell_preferences->priv->source_settings = g_settings_new ("org.gnome.rhythmbox.sources");
215 
216 	builder = rb_builder_load ("general-prefs.ui", shell_preferences);
217 
218 	rb_builder_boldify_label (builder, "visible_columns_label");
219 
220 	/* Columns */
221 	shell_preferences->priv->column_checks = g_hash_table_new (g_str_hash, g_str_equal);
222 	for (i = 0; i < G_N_ELEMENTS (column_checks); i++) {
223 		GtkWidget *widget;
224 		const char *name;
225 
226 		widget = GTK_WIDGET (gtk_builder_get_object (builder, column_checks[i].widget));
227 		/* XXX kind of nasty, we know rhythmdb_nice_elt_name_from_propid doesn't actually use the db */
228 		name = (const char *)rhythmdb_nice_elt_name_from_propid (NULL, column_checks[i].prop);
229 		g_assert (name != NULL);
230 
231 		g_signal_connect_object (widget, "toggled", G_CALLBACK (column_check_toggled_cb), shell_preferences, 0);
232 		g_object_set_data (G_OBJECT (widget), COLUMN_CHECK_PROP_NAME, (gpointer)name);
233 
234 		g_hash_table_insert (shell_preferences->priv->column_checks, (gpointer)name, widget);
235 	}
236 
237 	/* browser options */
238 	rb_builder_boldify_label (builder, "browser_views_label");
239 
240 	tmp = GTK_WIDGET (gtk_builder_get_object (builder, "library_browser_views_radio"));
241 	shell_preferences->priv->browser_views_group =
242 		g_slist_reverse (g_slist_copy (gtk_radio_button_get_group
243 					       (GTK_RADIO_BUTTON (tmp))));
244 
245 	gtk_notebook_append_page (GTK_NOTEBOOK (shell_preferences->priv->notebook),
246 				  GTK_WIDGET (gtk_builder_get_object (builder, "general_vbox")),
247 				  gtk_label_new (_("General")));
248 
249 	g_signal_connect_object (shell_preferences->priv->source_settings,
250 				 "changed",
251 				 G_CALLBACK (source_settings_changed_cb),
252 				 shell_preferences, 0);
253 	source_settings_changed_cb (shell_preferences->priv->source_settings,
254 				    "visible-columns",
255 				    shell_preferences);
256 	source_settings_changed_cb (shell_preferences->priv->source_settings,
257 				    "browser-views",
258 				    shell_preferences);
259 
260 	shell_preferences->priv->main_settings = g_settings_new ("org.gnome.rhythmbox");
261 
262 	/* box for stuff added by plugins */
263 	shell_preferences->priv->general_prefs_plugin_box =
264 		GTK_WIDGET (gtk_builder_get_object (builder, "plugin_box"));
265 
266 	g_object_unref (builder);
267 	builder = rb_builder_load ("playback-prefs.ui", shell_preferences);
268 
269 	/* playback preferences */
270 	rb_builder_boldify_label (builder, "backend_label");
271 	rb_builder_boldify_label (builder, "duration_label");
272 
273 	shell_preferences->priv->xfade_backend_check =
274 		GTK_WIDGET (gtk_builder_get_object (builder, "use_xfade_backend"));
275 	shell_preferences->priv->transition_duration =
276 		GTK_WIDGET (gtk_builder_get_object (builder, "duration"));
277 	shell_preferences->priv->playback_prefs_plugin_box =
278 		GTK_WIDGET (gtk_builder_get_object (builder, "plugin_box"));
279 
280 
281 	shell_preferences->priv->player_settings = g_settings_new ("org.gnome.rhythmbox.player");
282 	g_signal_connect_object (shell_preferences->priv->player_settings,
283 				 "changed",
284 				 G_CALLBACK (player_settings_changed_cb),
285 				 shell_preferences, 0);
286 	player_settings_changed_cb (shell_preferences->priv->player_settings,
287 				    "transition-time",
288 				    shell_preferences);
289 
290 
291 	g_settings_bind (shell_preferences->priv->player_settings,
292 			 "use-xfade-backend",
293 			 shell_preferences->priv->xfade_backend_check,
294 			 "active",
295 			 G_SETTINGS_BIND_DEFAULT);
296 
297 	/* unfortunately the GtkRange value can't be bound to a GSettings key.. */
298 	g_settings_bind (shell_preferences->priv->player_settings,
299 			 "use-xfade-backend",
300 			 shell_preferences->priv->transition_duration,
301 			 "sensitive",
302 			 G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET | G_SETTINGS_BIND_NO_SENSITIVITY);
303 
304 	g_signal_connect_object (gtk_builder_get_object (builder, "duration"),
305 				 "value-changed",
306 				 G_CALLBACK (transition_time_changed_cb),
307 				 shell_preferences, 0);
308 
309 	gtk_notebook_append_page (GTK_NOTEBOOK (shell_preferences->priv->notebook),
310 				  GTK_WIDGET (gtk_builder_get_object (builder, "playback_prefs_box")),
311 				  gtk_label_new (_("Playback")));
312 	g_object_unref (builder);
313 }
314 
315 static void
316 impl_dispose (GObject *object)
317 {
318 	RBShellPreferences *shell_preferences = RB_SHELL_PREFERENCES (object);
319 
320 	if (shell_preferences->priv->main_settings != NULL) {
321 		g_object_unref (shell_preferences->priv->main_settings);
322 		shell_preferences->priv->main_settings = NULL;
323 	}
324 
325 	if (shell_preferences->priv->source_settings != NULL) {
326 		g_object_unref (shell_preferences->priv->source_settings);
327 		shell_preferences->priv->source_settings = NULL;
328 	}
329 
330 	if (shell_preferences->priv->player_settings != NULL) {
331 		rb_settings_delayed_sync (shell_preferences->priv->player_settings, NULL, NULL, NULL);
332 		g_object_unref (shell_preferences->priv->player_settings);
333 		shell_preferences->priv->player_settings = NULL;
334 	}
335 
336 	G_OBJECT_CLASS (rb_shell_preferences_parent_class)->dispose (object);
337 }
338 
339 static void
340 impl_finalize (GObject *object)
341 {
342 	/*RBShellPreferences *shell_preferences = RB_SHELL_PREFERENCES (object);*/
343 
344 	/* anything to do here? */
345 
346 	G_OBJECT_CLASS (rb_shell_preferences_parent_class)->finalize (object);
347 }
348 
349 /**
350  * rb_shell_preferences_append_page:
351  * @prefs: the #RBShellPreferences instance
352  * @name: name of the page to append
353  * @widget: the #GtkWidget to use as the contents of the page
354  *
355  * Appends a new page to the preferences dialog notebook.
356  */
357 void
358 rb_shell_preferences_append_page (RBShellPreferences *prefs,
359 				  const char *name,
360 				  GtkWidget *widget)
361 {
362 	GtkWidget *label;
363 
364 	label = gtk_label_new (name);
365 	gtk_notebook_append_page (GTK_NOTEBOOK (prefs->priv->notebook),
366 				  widget,
367 				  label);
368 }
369 
370 static void
371 rb_shell_preferences_append_view_page (RBShellPreferences *prefs,
372 				       const char *name,
373 				       RBDisplayPage *page)
374 {
375 	GtkWidget *widget;
376 
377 	g_return_if_fail (RB_IS_SHELL_PREFERENCES (prefs));
378 	g_return_if_fail (RB_IS_DISPLAY_PAGE (page));
379 
380 	widget = rb_display_page_get_config_widget (page, prefs);
381 	if (!widget)
382 		return;
383 
384 	rb_shell_preferences_append_page (prefs, name, widget);
385 }
386 
387 /**
388  * rb_shell_preferences_new:
389  * @views: (element-type RB.Source) (transfer none): list of sources to check for preferences pages
390  *
391  * Creates the #RBShellPreferences instance, populating it with the
392  * preferences pages for the sources in the list.
393  *
394  * Return value: the #RBShellPreferences instance
395  */
396 GtkWidget *
397 rb_shell_preferences_new (GList *views)
398 {
399 	RBShellPreferences *shell_preferences;
400 
401 	shell_preferences = g_object_new (RB_TYPE_SHELL_PREFERENCES,
402 				          NULL, NULL);
403 
404 	g_return_val_if_fail (shell_preferences->priv != NULL, NULL);
405 
406 	for (; views; views = views->next)
407 	{
408 		char *name = NULL;
409 		g_object_get (views->data, "name", &name, NULL);
410 		if (name == NULL) {
411 			g_warning ("Page %p of type %s has no name",
412 				   views->data,
413 				   G_OBJECT_TYPE_NAME (views->data));
414 			continue;
415 		}
416 		rb_shell_preferences_append_view_page (shell_preferences,
417 						       name,
418 						       RB_DISPLAY_PAGE (views->data));
419 		g_free (name);
420 	}
421 
422 	return GTK_WIDGET (shell_preferences);
423 }
424 
425 static gboolean
426 rb_shell_preferences_window_delete_cb (GtkWidget *window,
427 				       GdkEventAny *event,
428 				       RBShellPreferences *shell_preferences)
429 {
430 	gtk_widget_hide (GTK_WIDGET (shell_preferences));
431 
432 	return TRUE;
433 }
434 
435 static void
436 rb_shell_preferences_response_cb (GtkDialog *dialog,
437 				  int response_id,
438 				  RBShellPreferences *shell_preferences)
439 {
440 	if (response_id == GTK_RESPONSE_CLOSE)
441 		gtk_widget_hide (GTK_WIDGET (shell_preferences));
442 }
443 
444 static void
445 column_check_toggled_cb (GtkWidget *widget, RBShellPreferences *preferences)
446 {
447 	const char *prop_name;
448 	const char *column;
449 	GVariantBuilder *b;
450 	GVariantIter *iter;
451 	GVariant *v;
452 
453 	prop_name = (const char *)g_object_get_data (G_OBJECT (widget), COLUMN_CHECK_PROP_NAME);
454 	g_assert (prop_name);
455 
456 	v = g_settings_get_value (preferences->priv->source_settings, "visible-columns");
457 
458 	/* remove from current column list */
459 	b = g_variant_builder_new (G_VARIANT_TYPE ("as"));
460 	iter = g_variant_iter_new (v);
461 	while (g_variant_iter_loop (iter, "s", &column)) {
462 		if (g_strcmp0 (column, prop_name) != 0) {
463 			g_variant_builder_add (b, "s", column);
464 		}
465 	}
466 	g_variant_unref (v);
467 
468 	/* if enabled, add it */
469 	if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget))) {
470 		g_variant_builder_add (b, "s", prop_name);
471 	}
472 
473 	v = g_variant_builder_end (b);
474 
475 	g_settings_set_value (preferences->priv->source_settings, "visible-columns", v);
476 
477 	g_variant_builder_unref (b);
478 }
479 
480 /**
481  * rb_shell_preferences_browser_views_activated_cb:
482  * @widget: the radio button that was selected
483  * @shell_preferences: the #RBShellPreferences instance
484  *
485  * Signal handler used for the radio buttons used to configure the
486  * visible browser views.
487  */
488 void
489 rb_shell_preferences_browser_views_activated_cb (GtkWidget *widget,
490 						 RBShellPreferences *shell_preferences)
491 {
492 	int index;
493 
494 	if (shell_preferences->priv->applying_settings)
495 		return;
496 
497 	index = g_slist_index (shell_preferences->priv->browser_views_group, widget);
498 
499 	g_settings_set_enum (shell_preferences->priv->source_settings, "browser-views", index);
500 }
501 
502 static void
503 source_settings_changed_cb (GSettings *settings, const char *key, RBShellPreferences *preferences)
504 {
505 	if (g_strcmp0 (key, "browser-views") == 0) {
506 		int view;
507 		GtkWidget *widget;
508 
509 		view = g_settings_get_enum (preferences->priv->source_settings, "browser-views");
510 		widget = GTK_WIDGET (g_slist_nth_data (preferences->priv->browser_views_group, view));
511 		preferences->priv->applying_settings = TRUE;
512 		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), TRUE);
513 		preferences->priv->applying_settings = FALSE;
514 
515 	} else if (g_strcmp0 (key, "visible-columns") == 0) {
516 		char **columns;
517 		GHashTableIter iter;
518 		gpointer name_ptr;
519 		gpointer widget_ptr;
520 
521 		columns = g_settings_get_strv (preferences->priv->source_settings, "visible-columns");
522 
523 		g_hash_table_iter_init (&iter, preferences->priv->column_checks);
524 		while (g_hash_table_iter_next (&iter, &name_ptr, &widget_ptr)) {
525 			gboolean enabled;
526 
527 			enabled = rb_str_in_strv (name_ptr, (const char **)columns);
528 			gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget_ptr), enabled);
529 		}
530 
531 		g_strfreev (columns);
532 	}
533 }
534 
535 static void
536 player_settings_changed_cb (GSettings *settings, const char *key, RBShellPreferences *preferences)
537 {
538 	if (g_strcmp0 (key, "transition-time") == 0) {
539 		gtk_range_set_value (GTK_RANGE (preferences->priv->transition_duration),
540 				     g_settings_get_double (settings, key));
541 	}
542 }
543 
544 static void
545 sync_transition_time (GSettings *settings, GtkRange *range)
546 {
547 	g_settings_set_double (settings,
548 			       "transition-time",
549 			       gtk_range_get_value (range));
550 }
551 
552 static void
553 transition_time_changed_cb (GtkRange *range, RBShellPreferences *preferences)
554 {
555 	rb_settings_delayed_sync (preferences->priv->player_settings,
556 				  (RBDelayedSyncFunc) sync_transition_time,
557 				  g_object_ref (range),
558 				  g_object_unref);
559 }
560 
561 static GtkWidget *
562 get_box_for_location (RBShellPreferences *prefs, RBShellPrefsUILocation location)
563 {
564 	switch (location) {
565 	case RB_SHELL_PREFS_UI_LOCATION_GENERAL:
566 		return prefs->priv->general_prefs_plugin_box;
567 	case RB_SHELL_PREFS_UI_LOCATION_PLAYBACK:
568 		return prefs->priv->playback_prefs_plugin_box;
569 	default:
570 		g_assert_not_reached();
571 	}
572 }
573 
574 /**
575  * rb_shell_preferences_add_widget:
576  * @prefs: the #RBShellPreferences
577  * @widget: the #GtkWidget to insert into the preferences window
578  * @location: the location at which to insert the widget
579  * @expand: whether the widget should be given extra space
580  * @fill: whether the widget should fill all space allocated to it
581  *
582  * Adds a widget to the preferences window.  See #gtk_box_pack_start for
583  * details on how the expand and fill parameters work.  This function can be
584  * used to add widgets to the 'general' and 'playback' pages.
585  */
586 void
587 rb_shell_preferences_add_widget (RBShellPreferences *prefs,
588 				 GtkWidget *widget,
589 				 RBShellPrefsUILocation location,
590 				 gboolean expand,
591 				 gboolean fill)
592 {
593 	GtkWidget *box;
594 
595 	box = get_box_for_location (prefs, location);
596 	gtk_box_pack_start (GTK_BOX (box), widget, expand, fill, 0);
597 }
598 
599 /**
600  * rb_shell_preferences_remove_widget:
601  * @prefs: the #RBShellPreferences
602  * @widget: the #GtkWidget to remove from the preferences window
603  * @location: the UI location to which the widget was originally added
604  *
605  * Removes a widget added with #rb_shell_preferences_add_widget from the preferences window.
606  */
607 void
608 rb_shell_preferences_remove_widget (RBShellPreferences *prefs,
609 				    GtkWidget *widget,
610 				    RBShellPrefsUILocation location)
611 {
612 	GtkWidget *box;
613 
614 	box = get_box_for_location (prefs, location);
615 	gtk_container_remove (GTK_CONTAINER (box), widget);
616 }
617 
618 #define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
619 
620 /**
621  * RBShellPrefsUILocation:
622  * @RB_SHELL_PREFS_UI_LOCATION_GENERAL: The "general" preferences page
623  * @RB_SHELL_PREFS_UI_LOCATION_PLAYBACK: THe "playback" preferences page
624  *
625  * Locations available for adding new widgets to the preferences dialog.
626  */
627 GType
628 rb_shell_prefs_ui_location_get_type (void)
629 {
630 	static GType etype = 0;
631 
632 	if (etype == 0)	{
633 		static const GEnumValue values[] = {
634 			ENUM_ENTRY (RB_SHELL_PREFS_UI_LOCATION_GENERAL, "general"),
635 			ENUM_ENTRY (RB_SHELL_PREFS_UI_LOCATION_PLAYBACK, "playback"),
636 			{ 0, 0, 0 }
637 		};
638 
639 		etype = g_enum_register_static ("RBShellPrefsUILocation", values);
640 	}
641 
642 	return etype;
643 }