Audacious  $Id:Doxyfile42802007-03-2104:39:00Znenolod$
ui_preferences.c
Go to the documentation of this file.
00001 /*  Audacious - Cross-platform multimedia player
00002  *  Copyright (C) 2005-2007  Audacious development team.
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; under version 3 of the License.
00007  *
00008  *  This program is distributed in the hope that it will be useful,
00009  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00010  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00011  *  GNU General Public License for more details.
00012  *
00013  *  You should have received a copy of the GNU General Public License
00014  *  along with this program.  If not, see <http://www.gnu.org/licenses>.
00015  *
00016  *  The Audacious team does not consider modular code linking to
00017  *  Audacious or using our public API to be a derived work.
00018  */
00019 
00020 #ifdef HAVE_CONFIG_H
00021 #  include "config.h"
00022 #endif
00023 
00024 #include <glib.h>
00025 #include <gtk/gtk.h>
00026 #include <string.h>
00027 #include <stddef.h>
00028 #include <stdio.h>
00029 #include <sys/types.h>
00030 #include <dirent.h>
00031 #include <unistd.h>
00032 #include <errno.h>
00033 #include <sys/types.h>
00034 #include <sys/stat.h>
00035 #include <gdk/gdkkeysyms.h>
00036 
00037 #include <libaudcore/hook.h>
00038 
00039 #include "audconfig.h"
00040 #include "compatibility.h"
00041 #include "debug.h"
00042 #include "i18n.h"
00043 #include "misc.h"
00044 #include "playback.h"
00045 #include "plugin.h"
00046 #include "pluginenum.h"
00047 #include "plugins.h"
00048 #include "effect.h"
00049 #include "general.h"
00050 #include "output.h"
00051 #include "playlist.h"
00052 #include "playlist-utils.h"
00053 #include "visualization.h"
00054 #include "util.h"
00055 #include "configdb.h"
00056 #include "preferences.h"
00057 
00058 #include "ui_preferences.h"
00059 
00060 #define TITLESTRING_UPDATE_TIMEOUT 3
00061 
00062 static void sw_volume_toggled (void);
00063 
00064 enum CategoryViewCols {
00065     CATEGORY_VIEW_COL_ICON,
00066     CATEGORY_VIEW_COL_NAME,
00067     CATEGORY_VIEW_COL_ID,
00068     CATEGORY_VIEW_N_COLS
00069 };
00070 
00071 enum PluginViewCols {
00072     PLUGIN_VIEW_COL_ACTIVE,
00073     PLUGIN_VIEW_COL_DESC,
00074     PLUGIN_VIEW_COL_FILENAME,
00075     PLUGIN_VIEW_COL_ID,
00076     PLUGIN_VIEW_COL_PLUGIN_PTR,
00077     PLUGIN_VIEW_N_COLS
00078 };
00079 
00080 enum PluginViewType {
00081     PLUGIN_VIEW_TYPE_INPUT,
00082     PLUGIN_VIEW_TYPE_GENERAL,
00083     PLUGIN_VIEW_TYPE_VIS,
00084     PLUGIN_VIEW_TYPE_EFFECT
00085 };
00086 
00087 typedef struct {
00088     const gchar *icon_path;
00089     const gchar *name;
00090 } Category;
00091 
00092 typedef struct {
00093     const gchar *name;
00094     const gchar *tag;
00095 } TitleFieldTag;
00096 
00097 typedef struct {
00098     gint x;
00099     gint y;
00100 } MenuPos;
00101 
00102 static /* GtkWidget * */ void * prefswin = NULL;
00103 static GtkWidget *filepopup_settings = NULL;
00104 static GtkWidget *category_treeview = NULL;
00105 static GtkWidget *category_notebook = NULL;
00106 GtkWidget *filepopupbutton = NULL;
00107 
00108 /* filepopup settings widgets */
00109 GtkWidget *filepopup_settings_cover_name_include;
00110 GtkWidget *filepopup_settings_cover_name_exclude;
00111 GtkWidget *filepopup_settings_recurse_for_cover;
00112 GtkWidget *filepopup_settings_recurse_for_cover_depth;
00113 GtkWidget *filepopup_settings_recurse_for_cover_depth_box;
00114 GtkWidget *filepopup_settings_use_file_cover;
00115 GtkWidget *filepopup_settings_showprogressbar;
00116 GtkWidget *filepopup_settings_delay;
00117 
00118 /* prefswin widgets */
00119 GtkWidget *titlestring_entry;
00120 GtkWidget *filepopup_for_tuple_settings_button;
00121 static gint titlestring_timeout_counter = 0;
00122 
00123 static Category categories[] = {
00124     {DATA_DIR "/images/audio.png",        N_("Audio")},
00125     {DATA_DIR "/images/replay_gain.png",  N_("Replay Gain")},
00126     {DATA_DIR "/images/connectivity.png", N_("Network")},
00127     {DATA_DIR "/images/playback.png",     N_("Playback")},
00128     {DATA_DIR "/images/playlist.png",     N_("Playlist")},
00129     {DATA_DIR "/images/plugins.png",      N_("Plugins")},
00130 };
00131 
00132 static gint n_categories = G_N_ELEMENTS(categories);
00133 
00134 static TitleFieldTag title_field_tags[] = {
00135     { N_("Artist")     , "${artist}" },
00136     { N_("Album")      , "${album}" },
00137     { N_("Title")      , "${title}" },
00138     { N_("Tracknumber"), "${track-number}" },
00139     { N_("Genre")      , "${genre}" },
00140     { N_("Filename")   , "${file-name}" },
00141     { N_("Filepath")   , "${file-path}" },
00142     { N_("Date")       , "${date}" },
00143     { N_("Year")       , "${year}" },
00144     { N_("Comment")    , "${comment}" },
00145     { N_("Codec")      , "${codec}" },
00146     { N_("Quality")    , "${quality}" },
00147 };
00148 static const guint n_title_field_tags = G_N_ELEMENTS(title_field_tags);
00149 
00150 static ComboBoxElements chardet_detector_presets[] = {
00151     { N_("None")     , N_("None") },
00152     { N_("Japanese") , N_("Japanese") },
00153     { N_("Taiwanese"), N_("Taiwanese") },
00154     { N_("Chinese")  , N_("Chinese") },
00155     { N_("Korean")   , N_("Korean") },
00156     { N_("Russian")  , N_("Russian") },
00157     { N_("Greek")    , N_("Greek") },
00158     { N_("Hebrew")   , N_("Hebrew") },
00159     { N_("Turkish")  , N_("Turkish") },
00160     { N_("Arabic")   , N_("Arabic") },
00161     { N_("Polish")   , N_("Polish") },
00162     { N_("Baltic")   , N_("Baltic") },
00163     { N_("Universal"), N_("Universal") }
00164 };
00165 
00166 static ComboBoxElements bitdepth_elements[] = {
00167     { GINT_TO_POINTER(16), "16" },
00168     { GINT_TO_POINTER(24), "24" },
00169     { GINT_TO_POINTER(32), "32" },
00170     {GINT_TO_POINTER (0), "Floating point"},
00171 };
00172 
00173 typedef struct {
00174     void *next;
00175     GtkWidget *container;
00176     const gchar * pg_name;
00177     const gchar * img_url;
00178 } CategoryQueueEntry;
00179 
00180 CategoryQueueEntry *category_queue = NULL;
00181 
00182 static PreferencesWidget audio_page_widgets[] = {
00183     {WIDGET_LABEL, N_("<b>Bit Depth</b>"), NULL, NULL, NULL, FALSE},
00184     {WIDGET_COMBO_BOX, N_("Output bit depth:"), &cfg.output_bit_depth, NULL,
00185                        N_("All streams will be converted to this bit depth.\n"
00186                           "This should be the max supported bit depth of\nthe sound card or output plugin."), FALSE,
00187                        {.combo = {bitdepth_elements, G_N_ELEMENTS(bitdepth_elements), TRUE}}, VALUE_INT},
00188     {WIDGET_LABEL, N_("<b>Volume Control</b>"), NULL, NULL, NULL, FALSE},
00189     {WIDGET_CHK_BTN, N_("Use software volume control"),
00190      & cfg.software_volume_control, sw_volume_toggled,
00191                      N_("Use software volume control. This may be useful for situations where your audio system does not support controlling the playback volume."), FALSE},
00192 };
00193 
00194 static PreferencesWidget rg_params_elements[] = {
00195     {WIDGET_SPIN_BTN, N_("Preamp:"), &cfg.replay_gain_preamp, NULL, NULL, FALSE, {.spin_btn = {-15, 15, 0.01, N_("dB")}}, VALUE_FLOAT},
00196     {WIDGET_SPIN_BTN, N_("Default gain:"), &cfg.default_gain, NULL, N_("This gain will be used if file doesn't contain Replay Gain metadata."), FALSE, {.spin_btn = {-15, 15, 0.01, N_("dB")}}, VALUE_FLOAT},
00197     {WIDGET_LABEL, N_("<span size=\"small\">Please remember that the most efficient way to prevent signal clipping is not to use positive values above.</span>"), NULL, NULL, NULL, FALSE, {.label = {"gtk-info"}}},
00198 };
00199 
00200 static PreferencesWidget replay_gain_page_widgets[] = {
00201     {WIDGET_LABEL, N_("<b>Replay Gain configuration</b>"), NULL, NULL, NULL, FALSE},
00202     {WIDGET_CHK_BTN, N_("Enable Replay Gain"), &cfg.enable_replay_gain, NULL, NULL, FALSE},
00203     {WIDGET_LABEL, N_("<b>Replay Gain mode</b>"), NULL, NULL, NULL, TRUE},
00204     {WIDGET_RADIO_BTN, N_("Track gain/peak"), &cfg.replay_gain_track, NULL, NULL, TRUE},
00205     {WIDGET_RADIO_BTN, N_("Album gain/peak"), &cfg.replay_gain_album, NULL, NULL, TRUE},
00206     {WIDGET_LABEL, N_("<b>Miscellaneous</b>"), NULL, NULL, NULL, TRUE},
00207     {WIDGET_CHK_BTN, N_("Enable peak info clipping prevention"), &cfg.enable_clipping_prevention, NULL,
00208                      N_("Use peak value from Replay Gain info for clipping prevention"), TRUE},
00209     {WIDGET_TABLE, NULL, NULL, NULL, NULL, TRUE, {.table = {rg_params_elements, G_N_ELEMENTS(rg_params_elements)}}},
00210 };
00211 
00212 static PreferencesWidget proxy_host_port_elements[] = {
00213     {WIDGET_ENTRY, N_("Proxy hostname:"), "proxy_host", NULL, NULL, FALSE, {.entry = {FALSE}}, VALUE_CFG_STRING},
00214     {WIDGET_ENTRY, N_("Proxy port:"), "proxy_port", NULL, NULL, FALSE, {.entry = {FALSE}}, VALUE_CFG_STRING},
00215 };
00216 
00217 static PreferencesWidget proxy_auth_elements[] = {
00218     {WIDGET_ENTRY, N_("Proxy username:"), "proxy_user", NULL, NULL, FALSE, {.entry = {FALSE}}, VALUE_CFG_STRING},
00219     {WIDGET_ENTRY, N_("Proxy password:"), "proxy_pass", NULL, NULL, FALSE, {.entry = {TRUE}}, VALUE_CFG_STRING},
00220 };
00221 
00222 static PreferencesWidget connectivity_page_widgets[] = {
00223     {WIDGET_LABEL, N_("<b>Proxy Configuration</b>"), NULL, NULL, NULL, FALSE},
00224     {WIDGET_CHK_BTN, N_("Enable proxy usage"), "use_proxy", NULL, NULL, FALSE,
00225      .cfg_type = VALUE_CFG_BOOLEAN},
00226     {WIDGET_TABLE, NULL, NULL, NULL, NULL, TRUE, {.table = {proxy_host_port_elements, G_N_ELEMENTS(proxy_host_port_elements)}}},
00227     {WIDGET_CHK_BTN, N_("Use authentication with proxy"), "proxy_use_auth",
00228      NULL, NULL, FALSE, .cfg_type = VALUE_CFG_BOOLEAN},
00229     {WIDGET_TABLE, NULL, NULL, NULL, NULL, TRUE, {.table = {proxy_auth_elements, G_N_ELEMENTS(proxy_auth_elements)}}},
00230     {WIDGET_LABEL, N_("<span size=\"small\">Changing these settings will require a restart of Audacious.</span>"), NULL, NULL, NULL, FALSE, {.label = {"gtk-dialog-warning"}}},
00231 };
00232 
00233 static PreferencesWidget playback_page_widgets[] = {
00234     {WIDGET_LABEL, N_("<b>Playback</b>"), NULL, NULL, NULL, FALSE},
00235     {WIDGET_CHK_BTN, N_("Continue playback on startup"), &cfg.resume_playback_on_startup, NULL,
00236         N_("When Audacious starts, automatically begin playing from the point where we stopped before."), FALSE},
00237     {WIDGET_CHK_BTN, N_("Don't advance in the playlist"), &cfg.no_playlist_advance, NULL,
00238         N_("When finished playing a song, don't automatically advance to the next."), FALSE},
00239     {WIDGET_CHK_BTN, N_("Clear current playlist when opening new files"),
00240      & cfg.clear_playlist, NULL, NULL, FALSE},
00241 };
00242 
00243 static PreferencesWidget chardet_elements[] = {
00244     {WIDGET_COMBO_BOX, N_("Auto character encoding detector for:"), &cfg.chardet_detector, NULL, NULL, TRUE,
00245         {.combo = {chardet_detector_presets, G_N_ELEMENTS(chardet_detector_presets),
00246                    #ifdef USE_CHARDET
00247                    TRUE
00248                    #else
00249                    FALSE
00250                    #endif
00251                    }}, VALUE_STRING},
00252     {WIDGET_ENTRY, N_("Fallback character encodings:"), &cfg.chardet_fallback, aud_config_chardet_update, N_("List of character encodings used for fall back conversion of metadata. If automatic character encoding detector failed or has been disabled, encodings in this list would be treated as candidates of the encoding of metadata, and fall back conversion from these encodings to UTF-8 would be attempted."), TRUE, {.entry = {FALSE}}, VALUE_STRING},
00253 };
00254 
00255 static PreferencesWidget playlist_page_widgets[] = {
00256     {WIDGET_LABEL, N_("<b>Metadata</b>"), NULL, NULL, NULL, FALSE},
00257     {WIDGET_TABLE, NULL, NULL, NULL, NULL, TRUE, {.table = {chardet_elements, G_N_ELEMENTS(chardet_elements)}}},
00258 };
00259 
00260 static void prefswin_page_queue_destroy(CategoryQueueEntry *ent);
00261 void create_plugin_preferences_page(PluginPreferences *settings);
00262 void destroy_plugin_preferences_page(PluginPreferences *settings);
00263 
00264 static void output_about (OutputPlugin * plugin)
00265 {
00266     if (plugin->about != NULL)
00267         plugin->about ();
00268 }
00269 
00270 static void output_configure (OutputPlugin * plugin)
00271 {
00272     if (plugin->configure != NULL)
00273         plugin->configure ();
00274 }
00275 
00276 static void
00277 change_category(GtkNotebook * notebook,
00278                 GtkTreeSelection * selection)
00279 {
00280     GtkTreeModel *model;
00281     GtkTreeIter iter;
00282     gint index;
00283 
00284     if (!gtk_tree_selection_get_selected(selection, &model, &iter))
00285         return;
00286 
00287     gtk_tree_model_get(model, &iter, CATEGORY_VIEW_COL_ID, &index, -1);
00288     gtk_notebook_set_current_page(notebook, index);
00289 }
00290 
00291 static void output_plugin_open_prefs (GtkComboBox * combo, void * unused)
00292 {
00293     output_configure (g_list_nth_data (get_output_list (),
00294      gtk_combo_box_get_active (combo)));
00295 }
00296 
00297 static void output_plugin_open_info (GtkComboBox * combo, void * unused)
00298 {
00299     output_about (g_list_nth_data (get_output_list (), gtk_combo_box_get_active
00300      (combo)));
00301 }
00302 
00303 static void
00304 plugin_toggle(GtkCellRendererToggle * cell,
00305               const gchar * path_str,
00306               gpointer data)
00307 {
00308     GtkTreeModel *model = GTK_TREE_MODEL(data);
00309     GtkTreeIter iter;
00310     GtkTreePath *path = gtk_tree_path_new_from_string(path_str);
00311     Plugin *plugin = NULL;
00312     gint plugin_type = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(data), "plugin_type"));
00313     gboolean enabled;
00314 
00315     /* get toggled iter */
00316     gtk_tree_model_get_iter(model, &iter, path);
00317 
00318     gtk_tree_model_get (model, & iter, PLUGIN_VIEW_COL_ACTIVE, & enabled,
00319      PLUGIN_VIEW_COL_PLUGIN_PTR, & plugin, -1);
00320     enabled = ! enabled;
00321 
00322     switch (plugin_type)
00323     {
00324     case PLUGIN_VIEW_TYPE_INPUT:
00325         plugin_set_enabled (plugin_by_header (plugin), enabled);
00326         break;
00327     case PLUGIN_VIEW_TYPE_GENERAL:
00328         general_plugin_enable (plugin_by_header (plugin), enabled);
00329         break;
00330     case PLUGIN_VIEW_TYPE_VIS:
00331         vis_plugin_enable (plugin_by_header (plugin), enabled);
00332         break;
00333     case PLUGIN_VIEW_TYPE_EFFECT:
00334         effect_plugin_enable (plugin_by_header (plugin), enabled);
00335         break;
00336     }
00337 
00338     gtk_list_store_set ((GtkListStore *) model, & iter, PLUGIN_VIEW_COL_ACTIVE,
00339      enabled, -1);
00340 
00341     if (plugin && plugin->settings && plugin->settings->type == PREFERENCES_PAGE) {
00342         if (enabled)
00343             create_plugin_preferences_page(plugin->settings);
00344         else
00345             destroy_plugin_preferences_page(plugin->settings);
00346     }
00347     /* clean up */
00348     gtk_tree_path_free(path);
00349 }
00350 
00351 static void on_output_plugin_cbox_changed (GtkComboBox * combo, void * unused)
00352 {
00353     set_current_output_plugin (g_list_nth_data (get_output_list (),
00354      gtk_combo_box_get_active (combo)));
00355 }
00356 
00357 static void
00358 on_output_plugin_cbox_realize(GtkComboBox * cbox,
00359                               gpointer data)
00360 {
00361     GList *olist = get_output_list();
00362     OutputPlugin * op;
00363     gint i = 0, selected = 0;
00364 
00365     if (olist == NULL) {
00366         gtk_widget_set_sensitive(GTK_WIDGET(cbox), FALSE);
00367         return;
00368     }
00369 
00370     for (i = 0; olist != NULL; i++, olist = g_list_next(olist)) {
00371         op = OUTPUT_PLUGIN(olist->data);
00372 
00373         if (olist->data == current_output_plugin)
00374             selected = i;
00375 
00376         gtk_combo_box_append_text(cbox, op->description);
00377     }
00378 
00379     gtk_combo_box_set_active(cbox, selected);
00380     g_signal_connect(cbox, "changed",
00381                      G_CALLBACK(on_output_plugin_cbox_changed), NULL);
00382 }
00383 
00384 static void
00385 on_plugin_view_realize(GtkTreeView * treeview,
00386                        GCallback callback,
00387                        gpointer data,
00388                        gint plugin_type)
00389 {
00390     GtkListStore *store;
00391     GtkTreeIter iter;
00392 
00393     GtkCellRenderer *renderer;
00394     GtkTreeViewColumn *column;
00395 
00396     GList *ilist;
00397     gchar *description[2];
00398     gint id = 0;
00399 
00400     GList *list = (GList *) data;
00401 
00402     store = gtk_list_store_new(PLUGIN_VIEW_N_COLS,
00403                                G_TYPE_BOOLEAN, G_TYPE_STRING,
00404                                G_TYPE_STRING, G_TYPE_INT, G_TYPE_POINTER);
00405     g_object_set_data(G_OBJECT(store), "plugin_type" , GINT_TO_POINTER(plugin_type));
00406 
00407     column = gtk_tree_view_column_new();
00408     gtk_tree_view_column_set_title(column, _("Enabled"));
00409     gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
00410     gtk_tree_view_column_set_spacing(column, 4);
00411     gtk_tree_view_column_set_resizable(column, FALSE);
00412     gtk_tree_view_column_set_fixed_width(column, 50);
00413 
00414     renderer = gtk_cell_renderer_toggle_new();
00415     g_signal_connect(renderer, "toggled",
00416                      G_CALLBACK(callback), store);
00417     gtk_tree_view_column_pack_start(column, renderer, TRUE);
00418     gtk_tree_view_column_set_attributes(column, renderer, "active",
00419                                         PLUGIN_VIEW_COL_ACTIVE, NULL);
00420 
00421     gtk_tree_view_append_column(treeview, column);
00422 
00423     column = gtk_tree_view_column_new();
00424     gtk_tree_view_column_set_title(column, _("Description"));
00425     gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
00426     gtk_tree_view_column_set_spacing(column, 4);
00427     gtk_tree_view_column_set_resizable(column, TRUE);
00428 
00429 
00430     renderer = gtk_cell_renderer_text_new();
00431     gtk_tree_view_column_pack_start(column, renderer, FALSE);
00432     gtk_tree_view_column_set_attributes(column, renderer,
00433                                         "text", PLUGIN_VIEW_COL_DESC, NULL);
00434     gtk_tree_view_append_column(treeview, column);
00435 
00436     column = gtk_tree_view_column_new();
00437 
00438     gtk_tree_view_column_set_title(column, _("Filename"));
00439     gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
00440     gtk_tree_view_column_set_spacing(column, 4);
00441     gtk_tree_view_column_set_resizable(column, TRUE);
00442 
00443     renderer = gtk_cell_renderer_text_new();
00444     gtk_tree_view_column_pack_start(column, renderer, TRUE);
00445     gtk_tree_view_column_set_attributes(column, renderer, "text",
00446                                         PLUGIN_VIEW_COL_FILENAME, NULL);
00447 
00448     gtk_tree_view_append_column(treeview, column);
00449 
00450     MOWGLI_ITER_FOREACH(ilist, list)
00451     {
00452         Plugin *plugin = PLUGIN(ilist->data);
00453         gboolean enabled = plugin_get_enabled (plugin_by_header (plugin));
00454 
00455         description[0] = g_strdup(plugin->description);
00456         description[1] = g_strdup(plugin->filename);
00457 
00458         gtk_list_store_append(store, &iter);
00459         gtk_list_store_set(store, &iter,
00460                            PLUGIN_VIEW_COL_ACTIVE, enabled,
00461                            PLUGIN_VIEW_COL_DESC, description[0],
00462                            PLUGIN_VIEW_COL_FILENAME, description[1],
00463                            PLUGIN_VIEW_COL_ID, id++,
00464                            PLUGIN_VIEW_COL_PLUGIN_PTR, plugin, -1);
00465 
00466         g_free(description[1]);
00467         g_free(description[0]);
00468     }
00469 
00470     gtk_tree_view_set_model(treeview, GTK_TREE_MODEL(store));
00471 }
00472 
00473 static void
00474 on_input_plugin_view_realize(GtkTreeView * treeview,
00475                              gpointer data)
00476 {
00477     on_plugin_view_realize (treeview, (GCallback) plugin_toggle, plugin_get_list(PLUGIN_TYPE_INPUT), PLUGIN_VIEW_TYPE_INPUT);
00478 }
00479 
00480 static void
00481 on_effect_plugin_view_realize(GtkTreeView * treeview,
00482                               gpointer data)
00483 {
00484     on_plugin_view_realize (treeview, (GCallback) plugin_toggle, plugin_get_list
00485      (PLUGIN_TYPE_EFFECT), PLUGIN_VIEW_TYPE_EFFECT);
00486 }
00487 
00488 static void
00489 on_general_plugin_view_realize(GtkTreeView * treeview,
00490                                gpointer data)
00491 {
00492     on_plugin_view_realize (treeview, (GCallback) plugin_toggle, plugin_get_list
00493      (PLUGIN_TYPE_GENERAL), PLUGIN_VIEW_TYPE_GENERAL);
00494 }
00495 
00496 static void
00497 on_vis_plugin_view_realize(GtkTreeView * treeview,
00498                            gpointer data)
00499 {
00500     on_plugin_view_realize(treeview, G_CALLBACK(plugin_toggle), plugin_get_list(PLUGIN_TYPE_VIS), PLUGIN_VIEW_TYPE_VIS);
00501 }
00502 
00503 static void
00504 editable_insert_text(GtkEditable * editable,
00505                      const gchar * text,
00506                      gint * pos)
00507 {
00508     gtk_editable_insert_text(editable, text, strlen(text), pos);
00509 }
00510 
00511 static void
00512 titlestring_tag_menu_callback(GtkMenuItem * menuitem,
00513                               gpointer data)
00514 {
00515     const gchar *separator = " - ";
00516     gint item = GPOINTER_TO_INT(data);
00517     gint pos;
00518 
00519     pos = gtk_editable_get_position(GTK_EDITABLE(titlestring_entry));
00520 
00521     /* insert separator as needed */
00522     if (g_utf8_strlen(gtk_entry_get_text(GTK_ENTRY(titlestring_entry)), -1) > 0)
00523         editable_insert_text(GTK_EDITABLE(titlestring_entry), separator, &pos);
00524 
00525     editable_insert_text(GTK_EDITABLE(titlestring_entry), _(title_field_tags[item].tag),
00526                          &pos);
00527 
00528     gtk_editable_set_position(GTK_EDITABLE(titlestring_entry), pos);
00529 }
00530 
00531 static void
00532 util_menu_position(GtkMenu * menu, gint * x, gint * y,
00533                    gboolean * push_in, gpointer data)
00534 {
00535     GtkRequisition requisition;
00536     gint screen_width;
00537     gint screen_height;
00538     MenuPos *pos = data;
00539 
00540     gtk_widget_size_request(GTK_WIDGET(menu), &requisition);
00541 
00542     screen_width = gdk_screen_width();
00543     screen_height = gdk_screen_height();
00544 
00545     *x = CLAMP(pos->x - 2, 0, MAX(0, screen_width - requisition.width));
00546     *y = CLAMP(pos->y - 2, 0, MAX(0, screen_height - requisition.height));
00547 }
00548 
00549 static void
00550 on_titlestring_help_button_clicked(GtkButton * button,
00551                                    gpointer data)
00552 {
00553     GtkMenu *menu;
00554     MenuPos *pos = g_newa(MenuPos, 1);
00555     GdkWindow *parent, *window;
00556 
00557     gint x_ro, y_ro;
00558     gint x_widget, y_widget;
00559     gint x_size, y_size;
00560 
00561     g_return_if_fail (button != NULL);
00562     g_return_if_fail (GTK_IS_MENU (data));
00563 
00564     parent = gtk_widget_get_parent_window(GTK_WIDGET(button));
00565     window = gtk_widget_get_window(GTK_WIDGET(button));
00566 
00567     gdk_drawable_get_size(parent, &x_size, &y_size);
00568     gdk_window_get_root_origin(window, &x_ro, &y_ro);
00569     gdk_window_get_position(window, &x_widget, &y_widget);
00570 
00571     pos->x = x_size + x_ro;
00572     pos->y = y_size + y_ro - 100;
00573 
00574     menu = GTK_MENU(data);
00575     gtk_menu_popup (menu, NULL, NULL, util_menu_position, pos,
00576                     0, GDK_CURRENT_TIME);
00577 }
00578 
00579 
00580 static void
00581 on_titlestring_entry_realize(GtkWidget * entry,
00582                              gpointer data)
00583 {
00584     gtk_entry_set_text(GTK_ENTRY(entry), cfg.gentitle_format);
00585 }
00586 
00587 static gboolean
00588 titlestring_timeout_proc (gpointer data)
00589 {
00590     titlestring_timeout_counter--;
00591 
00592     if(titlestring_timeout_counter <= 0) {
00593         titlestring_timeout_counter = 0;
00594         playlist_reformat_titles ();
00595         return FALSE;
00596     } else {
00597         return TRUE;
00598     }
00599 }
00600 
00601 static void
00602 on_titlestring_entry_changed(GtkWidget * entry,
00603                              gpointer data)
00604 {
00605     g_free(cfg.gentitle_format);
00606     cfg.gentitle_format = g_strdup(gtk_entry_get_text(GTK_ENTRY(entry)));
00607 
00608     if(titlestring_timeout_counter == 0) {
00609         g_timeout_add_seconds (1, (GSourceFunc) titlestring_timeout_proc, NULL);
00610     }
00611 
00612     titlestring_timeout_counter = TITLESTRING_UPDATE_TIMEOUT;
00613 }
00614 
00615 static void
00616 on_titlestring_cbox_realize(GtkWidget * cbox,
00617                             gpointer data)
00618 {
00619     gtk_combo_box_set_active(GTK_COMBO_BOX(cbox), cfg.titlestring_preset);
00620     gtk_widget_set_sensitive(GTK_WIDGET(data),
00621                              (cfg.titlestring_preset == (gint)n_titlestring_presets));
00622 }
00623 
00624 static void
00625 on_titlestring_cbox_changed(GtkWidget * cbox,
00626                             gpointer data)
00627 {
00628     gint position = gtk_combo_box_get_active(GTK_COMBO_BOX(cbox));
00629 
00630     cfg.titlestring_preset = position;
00631     gtk_widget_set_sensitive(GTK_WIDGET(data), (position == 6));
00632 
00633     playlist_reformat_titles ();
00634 }
00635 
00636 static void
00637 on_font_btn_realize(GtkFontButton * button, gchar **cfg)
00638 {
00639     gtk_font_button_set_font_name(button, *cfg);
00640 }
00641 
00642 static void
00643 on_font_btn_font_set(GtkFontButton * button, gchar **config)
00644 {
00645     g_free(*config);
00646     *config = g_strdup(gtk_font_button_get_font_name(button));
00647     AUDDBG("Returned font name: \"%s\"\n", *config);
00648     void (*callback) (void) = g_object_get_data(G_OBJECT(button), "callback");
00649     if (callback != NULL) callback();
00650 }
00651 
00652 static void
00653 plugin_preferences_ok(GtkWidget *widget, PluginPreferences *settings)
00654 {
00655     if (settings->apply)
00656         settings->apply();
00657 
00658     gtk_widget_destroy(GTK_WIDGET(settings->data));
00659 }
00660 
00661 static void
00662 plugin_preferences_apply(GtkWidget *widget, PluginPreferences *settings)
00663 {
00664     if (settings->apply)
00665         settings->apply();
00666 }
00667 
00668 static void
00669 plugin_preferences_cancel(GtkWidget *widget, PluginPreferences *settings)
00670 {
00671     if (settings->cancel)
00672         settings->cancel();
00673 
00674     gtk_widget_destroy(GTK_WIDGET(settings->data));
00675 }
00676 
00677 static void
00678 plugin_preferences_destroy(GtkWidget *widget, PluginPreferences *settings)
00679 {
00680     gtk_widget_destroy(widget);
00681 
00682     if (settings->cleanup)
00683         settings->cleanup();
00684 
00685     settings->data = NULL;
00686 }
00687 
00688 static void
00689 create_plugin_preferences(PluginPreferences *settings)
00690 {
00691     GtkWidget *window;
00692     GtkWidget *vbox, *bbox, *ok, *apply, *cancel;
00693 
00694     if (settings->data != NULL) {
00695         gtk_widget_show(GTK_WIDGET(settings->data));
00696         return;
00697     }
00698 
00699     if (settings->init)
00700         settings->init();
00701 
00702     window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
00703     gtk_window_set_type_hint(GTK_WINDOW(window), GDK_WINDOW_TYPE_HINT_DIALOG);
00704     gtk_window_set_title(GTK_WINDOW(window), _(settings->title));
00705     gtk_container_set_border_width(GTK_CONTAINER(window), 10);
00706 
00707     g_signal_connect(G_OBJECT(window), "destroy",
00708                      G_CALLBACK(plugin_preferences_destroy), settings);
00709 
00710     vbox = gtk_vbox_new(FALSE, 10);
00711     create_widgets(GTK_BOX(vbox), settings->prefs, settings->n_prefs);
00712     gtk_container_add(GTK_CONTAINER(window), vbox);
00713 
00714     bbox = gtk_hbutton_box_new();
00715     gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
00716     gtk_box_set_spacing(GTK_BOX(bbox), 5);
00717     gtk_box_pack_start(GTK_BOX(vbox), bbox, FALSE, FALSE, 0);
00718 
00719     ok = gtk_button_new_from_stock(GTK_STOCK_OK);
00720     g_signal_connect(G_OBJECT(ok), "clicked",
00721                      G_CALLBACK(plugin_preferences_ok), settings);
00722     gtk_box_pack_start(GTK_BOX(bbox), ok, TRUE, TRUE, 0);
00723     gtk_widget_set_can_default (ok, TRUE);
00724     gtk_widget_grab_default(ok);
00725 
00726     apply = gtk_button_new_from_stock(GTK_STOCK_APPLY);
00727     g_signal_connect(G_OBJECT(apply), "clicked",
00728                      G_CALLBACK(plugin_preferences_apply), settings);
00729     gtk_box_pack_start(GTK_BOX(bbox), apply, TRUE, TRUE, 0);
00730 
00731     cancel = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
00732     g_signal_connect(G_OBJECT(cancel), "clicked",
00733                      G_CALLBACK(plugin_preferences_cancel), settings);
00734     gtk_box_pack_start(GTK_BOX(bbox), cancel, TRUE, TRUE, 0);
00735 
00736     gtk_window_set_transient_for(GTK_WINDOW(window), GTK_WINDOW(prefswin));
00737     gtk_widget_show_all(window);
00738     settings->data = (gpointer)window;
00739 }
00740 
00741 static void
00742 plugin_treeview_open_prefs(GtkTreeView *treeview)
00743 {
00744     GtkTreeSelection *selection;
00745     GtkTreeModel *model;
00746     GtkTreeIter iter;
00747     Plugin *plugin = NULL;
00748 
00749     selection = gtk_tree_view_get_selection(treeview);
00750     if (!gtk_tree_selection_get_selected(selection, &model, &iter))
00751         return;
00752     gtk_tree_model_get(model, &iter, PLUGIN_VIEW_COL_PLUGIN_PTR, &plugin, -1);
00753 
00754     g_return_if_fail(plugin != NULL);
00755     g_return_if_fail((plugin->configure != NULL) ||
00756                      ((plugin->settings != NULL) && (plugin->settings->type == PREFERENCES_WINDOW)));
00757 
00758     if (plugin->configure != NULL)
00759         plugin->configure();
00760     else
00761         create_plugin_preferences(plugin->settings);
00762 }
00763 
00764 static void
00765 plugin_treeview_open_info(GtkTreeView *treeview)
00766 {
00767     GtkTreeSelection *selection;
00768     GtkTreeModel *model;
00769     GtkTreeIter iter;
00770     Plugin *plugin = NULL;
00771 
00772     selection = gtk_tree_view_get_selection(treeview);
00773     if (!gtk_tree_selection_get_selected(selection, &model, &iter))
00774         return;
00775     gtk_tree_model_get(model, &iter, PLUGIN_VIEW_COL_PLUGIN_PTR, &plugin, -1);
00776 
00777     g_return_if_fail(plugin != NULL);
00778     plugin->about();
00779 }
00780 
00781 static void
00782 plugin_treeview_enable_prefs(GtkTreeView * treeview, GtkButton * button)
00783 {
00784     GtkTreeSelection *selection;
00785     GtkTreeModel *model;
00786     GtkTreeIter iter;
00787     Plugin *plugin = NULL;
00788 
00789     selection = gtk_tree_view_get_selection(treeview);
00790     if (!gtk_tree_selection_get_selected(selection, &model, &iter))
00791         return;
00792 
00793     gtk_tree_model_get(model, &iter, PLUGIN_VIEW_COL_PLUGIN_PTR, &plugin, -1);
00794 
00795     g_return_if_fail(plugin != NULL);
00796 
00797     gtk_widget_set_sensitive(GTK_WIDGET(button),
00798                              ((plugin->configure != NULL) ||
00799                              (plugin->settings ? (plugin->settings->type == PREFERENCES_WINDOW) : FALSE)));
00800 }
00801 
00802 static void
00803 plugin_treeview_enable_info(GtkTreeView * treeview, GtkButton * button)
00804 {
00805     GtkTreeSelection *selection;
00806     GtkTreeModel *model;
00807     GtkTreeIter iter;
00808     Plugin *plugin = NULL;
00809 
00810     selection = gtk_tree_view_get_selection(treeview);
00811     if (!gtk_tree_selection_get_selected(selection, &model, &iter))
00812         return;
00813 
00814     gtk_tree_model_get(model, &iter, PLUGIN_VIEW_COL_PLUGIN_PTR, &plugin, -1);
00815 
00816     g_return_if_fail(plugin != NULL);
00817 
00818     gtk_widget_set_sensitive(GTK_WIDGET(button), plugin->about != NULL);
00819 }
00820 
00821 
00822 static void
00823 output_plugin_enable_info(GtkComboBox * cbox, GtkButton * button)
00824 {
00825     GList *plist;
00826 
00827     gint id = gtk_combo_box_get_active(cbox);
00828 
00829     plist = get_output_list();
00830     plist = g_list_nth(plist, id);
00831 
00832     gtk_widget_set_sensitive(GTK_WIDGET(button),
00833                              OUTPUT_PLUGIN(plist->data)->about != NULL);
00834 }
00835 
00836 static void
00837 output_plugin_enable_prefs(GtkComboBox * cbox, GtkButton * button)
00838 {
00839     GList *plist;
00840     gint id = gtk_combo_box_get_active(cbox);
00841 
00842     plist = get_output_list();
00843     plist = g_list_nth(plist, id);
00844 
00845     gtk_widget_set_sensitive(GTK_WIDGET(button),
00846                              OUTPUT_PLUGIN(plist->data)->configure != NULL);
00847 }
00848 
00849 static void
00850 on_output_plugin_bufsize_realize(GtkSpinButton *button,
00851                                  gpointer data)
00852 {
00853     gtk_spin_button_set_value(button, cfg.output_buffer_size);
00854 }
00855 
00856 static void
00857 on_output_plugin_bufsize_value_changed(GtkSpinButton *button,
00858                                        gpointer data)
00859 {
00860     cfg.output_buffer_size = gtk_spin_button_get_value_as_int(button);
00861 }
00862 
00863 static void
00864 on_spin_btn_realize_gint(GtkSpinButton *button, gint *cfg)
00865 {
00866     gtk_spin_button_set_value(button, *cfg);
00867 }
00868 
00869 static void
00870 on_spin_btn_changed_gint(GtkSpinButton *button, gint *cfg)
00871 {
00872     *cfg = gtk_spin_button_get_value_as_int(button);
00873 }
00874 
00875 static void
00876 on_spin_btn_realize_gfloat(GtkSpinButton *button, gfloat *cfg)
00877 {
00878      gtk_spin_button_set_value(button, (gdouble) *cfg);
00879 }
00880 
00881 static void
00882 on_spin_btn_changed_gfloat(GtkSpinButton *button, gfloat *cfg)
00883 {
00884     *cfg = (gfloat) gtk_spin_button_get_value(button);
00885 }
00886 
00887 
00888 static void
00889 on_category_treeview_realize(GtkTreeView * treeview,
00890                              GtkNotebook * notebook)
00891 {
00892     GtkListStore *store;
00893     GtkCellRenderer *renderer;
00894     GtkTreeViewColumn *column;
00895     GtkTreeSelection *selection;
00896     GtkTreeIter iter;
00897     GdkPixbuf *img;
00898     CategoryQueueEntry *qlist;
00899     gint i;
00900 
00901     column = gtk_tree_view_column_new();
00902     gtk_tree_view_column_set_title(column, _("Category"));
00903     gtk_tree_view_append_column(treeview, column);
00904     gtk_tree_view_column_set_spacing(column, 2);
00905 
00906     renderer = gtk_cell_renderer_pixbuf_new();
00907     gtk_tree_view_column_pack_start(column, renderer, FALSE);
00908     gtk_tree_view_column_set_attributes(column, renderer, "pixbuf", 0, NULL);
00909 
00910     renderer = gtk_cell_renderer_text_new();
00911     gtk_tree_view_column_pack_start(column, renderer, FALSE);
00912     gtk_tree_view_column_set_attributes(column, renderer, "text", 1, NULL);
00913 
00914     gint width, height;
00915     gtk_widget_get_size_request(GTK_WIDGET(treeview), &width, &height);
00916     g_object_set(G_OBJECT(renderer), "wrap-width", width - 64 - 24, "wrap-mode",
00917      PANGO_WRAP_WORD_CHAR, NULL);
00918 
00919     store = gtk_list_store_new(CATEGORY_VIEW_N_COLS,
00920                                GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_INT);
00921     gtk_tree_view_set_model(treeview, GTK_TREE_MODEL(store));
00922 
00923     for (i = 0; i < n_categories; i++) {
00924         img = gdk_pixbuf_new_from_file(categories[i].icon_path, NULL);
00925         gtk_list_store_append(store, &iter);
00926         gtk_list_store_set(store, &iter,
00927                            CATEGORY_VIEW_COL_ICON, img,
00928                            CATEGORY_VIEW_COL_NAME,
00929                            gettext(categories[i].name), CATEGORY_VIEW_COL_ID,
00930                            i, -1);
00931         g_object_unref(img);
00932     }
00933 
00934     selection = gtk_tree_view_get_selection(treeview);
00935 
00936     g_signal_connect_swapped(selection, "changed",
00937                              G_CALLBACK(change_category), notebook);
00938 
00939     /* mark the treeview widget as available to third party plugins */
00940     category_treeview = GTK_WIDGET(treeview);
00941 
00942     /* prefswin_page_queue_destroy already pops the queue forward for us. */
00943     for (qlist = category_queue; qlist != NULL; qlist = category_queue)
00944     {
00945         CategoryQueueEntry *ent = (CategoryQueueEntry *) qlist;
00946 
00947         prefswin_page_new(ent->container, ent->pg_name, ent->img_url);
00948         prefswin_page_queue_destroy(ent);
00949     }
00950 }
00951 
00952 static void
00953 on_show_filepopup_for_tuple_realize(GtkToggleButton * button, gpointer data)
00954 {
00955     gtk_toggle_button_set_active(button, cfg.show_filepopup_for_tuple);
00956     filepopupbutton = GTK_WIDGET(button);
00957 
00958     gtk_widget_set_sensitive(filepopup_for_tuple_settings_button, cfg.show_filepopup_for_tuple);
00959 }
00960 
00961 static void
00962 on_show_filepopup_for_tuple_toggled(GtkToggleButton * button, gpointer data)
00963 {
00964     cfg.show_filepopup_for_tuple = gtk_toggle_button_get_active(button);
00965 
00966     gtk_widget_set_sensitive(filepopup_for_tuple_settings_button, cfg.show_filepopup_for_tuple);
00967 }
00968 
00969 static void
00970 on_recurse_for_cover_toggled(GtkToggleButton *button, gpointer data)
00971 {
00972     gtk_widget_set_sensitive(GTK_WIDGET(data),
00973                              gtk_toggle_button_get_active(button));
00974 }
00975 
00976 static void
00977 on_filepopup_for_tuple_settings_clicked(GtkButton *button, gpointer data)
00978 {
00979     gtk_entry_set_text(GTK_ENTRY(filepopup_settings_cover_name_include), cfg.cover_name_include);
00980     gtk_entry_set_text(GTK_ENTRY(filepopup_settings_cover_name_exclude), cfg.cover_name_exclude);
00981     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(filepopup_settings_recurse_for_cover), cfg.recurse_for_cover);
00982     gtk_spin_button_set_value(GTK_SPIN_BUTTON(filepopup_settings_recurse_for_cover_depth), cfg.recurse_for_cover_depth);
00983     on_recurse_for_cover_toggled(GTK_TOGGLE_BUTTON(filepopup_settings_recurse_for_cover), filepopup_settings_recurse_for_cover_depth_box);
00984     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(filepopup_settings_use_file_cover), cfg.use_file_cover);
00985     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(filepopup_settings_showprogressbar), cfg.filepopup_showprogressbar);
00986     gtk_spin_button_set_value(GTK_SPIN_BUTTON(filepopup_settings_delay), cfg.filepopup_delay);
00987 
00988     gtk_widget_show(filepopup_settings);
00989 }
00990 
00991 static void
00992 on_filepopup_settings_ok_clicked(GtkButton *button, gpointer data)
00993 {
00994     g_free(cfg.cover_name_include);
00995     cfg.cover_name_include = g_strdup(gtk_entry_get_text(GTK_ENTRY(filepopup_settings_cover_name_include)));
00996 
00997     g_free(cfg.cover_name_exclude);
00998     cfg.cover_name_exclude = g_strdup(gtk_entry_get_text(GTK_ENTRY(filepopup_settings_cover_name_exclude)));
00999 
01000     cfg.recurse_for_cover = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(filepopup_settings_recurse_for_cover));
01001     cfg.recurse_for_cover_depth = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(filepopup_settings_recurse_for_cover_depth));
01002     cfg.use_file_cover = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(filepopup_settings_use_file_cover));
01003     cfg.filepopup_showprogressbar = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(filepopup_settings_showprogressbar));
01004     cfg.filepopup_delay = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(filepopup_settings_delay));
01005 
01006     gtk_widget_hide(filepopup_settings);
01007 }
01008 
01009 static void
01010 on_filepopup_settings_cancel_clicked(GtkButton *button, gpointer data)
01011 {
01012     gtk_widget_hide(filepopup_settings);
01013 }
01014 
01015 static void
01016 on_toggle_button_toggled(GtkToggleButton * button, gboolean *cfg)
01017 {
01018     *cfg = gtk_toggle_button_get_active(button);
01019     void (*callback) (void) = g_object_get_data(G_OBJECT(button), "callback");
01020     if (callback != NULL) callback();
01021     GtkWidget *child = g_object_get_data(G_OBJECT(button), "child");
01022     if (child) gtk_widget_set_sensitive(GTK_WIDGET(child), *cfg);
01023 }
01024 
01025 static void
01026 on_toggle_button_realize(GtkToggleButton * button, gboolean *cfg)
01027 {
01028     gtk_toggle_button_set_active(button, cfg ? *cfg : FALSE);
01029     GtkWidget *child = g_object_get_data(G_OBJECT(button), "child");
01030     if (child) gtk_widget_set_sensitive(GTK_WIDGET(child), cfg ? *cfg : FALSE);
01031 }
01032 
01033 static void
01034 on_toggle_button_cfg_toggled(GtkToggleButton *button, gchar *cfg)
01035 {
01036     g_return_if_fail(cfg != NULL);
01037 
01038     mcs_handle_t *db;
01039     gboolean ret = gtk_toggle_button_get_active(button);
01040 
01041     db = cfg_db_open();
01042     cfg_db_set_bool(db, NULL, cfg, ret);
01043     cfg_db_close(db);
01044 }
01045 
01046 static void
01047 on_toggle_button_cfg_realize(GtkToggleButton *button, gchar *cfg)
01048 {
01049     mcs_handle_t *db;
01050     gboolean ret;
01051 
01052     g_return_if_fail(cfg != NULL);
01053 
01054     db = cfg_db_open();
01055 
01056     if (cfg_db_get_bool(db, NULL, cfg, &ret) != FALSE)
01057         gtk_toggle_button_set_active(button, ret);
01058 
01059     cfg_db_close(db);
01060 }
01061 
01062 static void
01063 on_entry_realize(GtkEntry *entry, gchar **cfg)
01064 {
01065     g_return_if_fail(cfg != NULL);
01066 
01067     if (*cfg)
01068         gtk_entry_set_text(entry, *cfg);
01069 }
01070 
01071 static void
01072 on_entry_changed(GtkEntry *entry, gchar **cfg)
01073 {
01074     void (*callback) (void) = g_object_get_data(G_OBJECT(entry), "callback");
01075     const gchar *ret;
01076 
01077     g_return_if_fail(cfg != NULL);
01078 
01079     g_free(*cfg);
01080 
01081     ret = gtk_entry_get_text(entry);
01082 
01083     if (ret == NULL)
01084         *cfg = g_strdup("");
01085     else
01086         *cfg = g_strdup(ret);
01087 
01088     if (callback != NULL) callback();
01089 }
01090 
01091 static void
01092 on_entry_cfg_realize(GtkEntry *entry, gchar *cfg)
01093 {
01094     mcs_handle_t *db;
01095     gchar *ret;
01096 
01097     g_return_if_fail(cfg != NULL);
01098 
01099     db = cfg_db_open();
01100 
01101     if (cfg_db_get_string(db, NULL, cfg, &ret) != FALSE)
01102         gtk_entry_set_text(entry, ret);
01103 
01104     cfg_db_close(db);
01105 }
01106 
01107 static void
01108 on_entry_cfg_changed(GtkEntry *entry, gchar *cfg)
01109 {
01110     mcs_handle_t *db;
01111     gchar *ret = g_strdup(gtk_entry_get_text(entry));
01112 
01113     g_return_if_fail(cfg != NULL);
01114 
01115     db = cfg_db_open();
01116     cfg_db_set_string(db, NULL, cfg, ret);
01117     cfg_db_close(db);
01118 
01119     g_free(ret);
01120 }
01121 
01122 static void
01123 on_cbox_changed_int(GtkComboBox * combobox, PreferencesWidget *widget)
01124 {
01125     gint position = 0;
01126 
01127     position = gtk_combo_box_get_active(GTK_COMBO_BOX(combobox));
01128     *((gint *)widget->cfg) = GPOINTER_TO_INT(widget->data.combo.elements[position].value);
01129 }
01130 
01131 static void
01132 on_cbox_changed_string(GtkComboBox * combobox, PreferencesWidget *widget)
01133 {
01134     gint position = 0;
01135 
01136     position = gtk_combo_box_get_active(GTK_COMBO_BOX(combobox));
01137     
01138     g_free(*((gchar **)widget->cfg));
01139     
01140     *((gchar **)widget->cfg) = g_strdup(widget->data.combo.elements[position].value);
01141 }
01142 
01143 static void
01144 on_cbox_realize(GtkComboBox *combobox, PreferencesWidget * widget)
01145 {
01146     guint i=0,index=0;
01147 
01148     for(i=0; i<widget->data.combo.n_elements; i++) {
01149         gtk_combo_box_append_text(combobox, _(widget->data.combo.elements[i].label));
01150     }
01151 
01152     if (widget->data.combo.enabled) {
01153         switch (widget->cfg_type) {
01154             case VALUE_INT:
01155                 g_signal_connect(combobox, "changed",
01156                                  G_CALLBACK(on_cbox_changed_int), widget);
01157                 for(i=0; i<widget->data.combo.n_elements; i++) {
01158                     if (GPOINTER_TO_INT(widget->data.combo.elements[i].value) == *((gint *) widget->cfg)) {
01159                         index = i;
01160                         break;
01161                     }
01162                 }
01163                 break;
01164             case VALUE_STRING:
01165                 g_signal_connect(combobox, "changed",
01166                                  G_CALLBACK(on_cbox_changed_string), widget);
01167                 for(i=0; i<widget->data.combo.n_elements; i++) {
01168                     if(!strcmp((gchar *)widget->data.combo.elements[i].value, *((gchar **)widget->cfg))) {
01169                         index = i;
01170                         break;
01171                     }
01172                 }
01173                 break;
01174             case VALUE_NULL:
01175                 break;
01176             default:
01177                 g_warning("Unhandled cbox value type");
01178                 break;
01179         }
01180         gtk_combo_box_set_active(GTK_COMBO_BOX(combobox), index);
01181     } else {
01182         gtk_combo_box_set_active(GTK_COMBO_BOX(combobox), -1);
01183         gtk_widget_set_sensitive(GTK_WIDGET(combobox), 0);
01184     }
01185 }
01186 
01187 void
01188 create_filepopup_settings(void)
01189 {
01190     GtkWidget *vbox;
01191     GtkWidget *table;
01192 
01193     GtkWidget *label_cover_retrieve;
01194     GtkWidget *label_cover_search;
01195     GtkWidget *label_exclude;
01196     GtkWidget *label_include;
01197     GtkWidget *label_search_depth;
01198     GtkWidget *label_misc;
01199     GtkWidget *label_delay;
01200 
01201     GtkObject *recurse_for_cover_depth_adj;
01202     GtkObject *delay_adj;
01203     GtkWidget *alignment;
01204 
01205     GtkWidget *hbox;
01206     GtkWidget *hbuttonbox;
01207     GtkWidget *btn_cancel;
01208     GtkWidget *btn_ok;
01209 
01210     filepopup_settings = gtk_window_new(GTK_WINDOW_TOPLEVEL);
01211     gtk_container_set_border_width(GTK_CONTAINER(filepopup_settings), 12);
01212     gtk_window_set_title(GTK_WINDOW(filepopup_settings), _("Popup Information Settings"));
01213     gtk_window_set_position(GTK_WINDOW(filepopup_settings), GTK_WIN_POS_CENTER_ON_PARENT);
01214     gtk_window_set_skip_taskbar_hint(GTK_WINDOW(filepopup_settings), TRUE);
01215     gtk_window_set_type_hint(GTK_WINDOW(filepopup_settings), GDK_WINDOW_TYPE_HINT_DIALOG);
01216     gtk_window_set_transient_for(GTK_WINDOW(filepopup_settings), GTK_WINDOW(prefswin));
01217 
01218     vbox = gtk_vbox_new(FALSE, 12);
01219     gtk_container_add(GTK_CONTAINER(filepopup_settings), vbox);
01220 
01221     label_cover_retrieve = gtk_label_new(_("<b>Cover image retrieve</b>"));
01222     gtk_box_pack_start(GTK_BOX(vbox), label_cover_retrieve, FALSE, FALSE, 0);
01223     gtk_label_set_use_markup(GTK_LABEL(label_cover_retrieve), TRUE);
01224     gtk_misc_set_alignment(GTK_MISC(label_cover_retrieve), 0, 0.5);
01225 
01226     label_cover_search = gtk_label_new(_("While searching for the album's cover, Audacious looks for certain words in the filename. You can specify those words in the lists below, separated using commas."));
01227     gtk_box_pack_start(GTK_BOX(vbox), label_cover_search, FALSE, FALSE, 0);
01228     gtk_label_set_line_wrap(GTK_LABEL(label_cover_search), TRUE);
01229     gtk_misc_set_alignment(GTK_MISC(label_cover_search), 0, 0);
01230     gtk_misc_set_padding(GTK_MISC(label_cover_search), 12, 0);
01231 
01232     table = gtk_table_new(2, 2, FALSE);
01233     gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 0);
01234     gtk_table_set_row_spacings(GTK_TABLE(table), 4);
01235     gtk_table_set_col_spacings(GTK_TABLE(table), 4);
01236 
01237     filepopup_settings_cover_name_include = gtk_entry_new();
01238     gtk_table_attach(GTK_TABLE(table), filepopup_settings_cover_name_include, 1, 2, 0, 1,
01239                      (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
01240                      (GtkAttachOptions) (0), 0, 0);
01241     gtk_entry_set_activates_default(GTK_ENTRY(filepopup_settings_cover_name_include), TRUE);
01242 
01243     label_exclude = gtk_label_new(_("Exclude:"));
01244     gtk_table_attach(GTK_TABLE(table), label_exclude, 0, 1, 1, 2,
01245                      (GtkAttachOptions) (0),
01246                      (GtkAttachOptions) (0), 0, 0);
01247     gtk_misc_set_alignment(GTK_MISC(label_exclude), 0, 0.5);
01248     gtk_misc_set_padding(GTK_MISC(label_exclude), 12, 0);
01249 
01250     label_include = gtk_label_new(_("Include:"));
01251     gtk_table_attach(GTK_TABLE(table), label_include, 0, 1, 0, 1,
01252                      (GtkAttachOptions) (0),
01253                      (GtkAttachOptions) (0), 0, 0);
01254     gtk_misc_set_alignment(GTK_MISC(label_include), 0, 0.5);
01255     gtk_misc_set_padding(GTK_MISC(label_include), 12, 0);
01256 
01257     filepopup_settings_cover_name_exclude = gtk_entry_new();
01258     gtk_table_attach(GTK_TABLE(table), filepopup_settings_cover_name_exclude, 1, 2, 1, 2,
01259                      (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
01260                      (GtkAttachOptions) (0), 0, 0);
01261     gtk_entry_set_activates_default(GTK_ENTRY(filepopup_settings_cover_name_exclude), TRUE);
01262 
01263     alignment = gtk_alignment_new(0.5, 0.5, 1, 1);
01264     gtk_box_pack_start(GTK_BOX(vbox), alignment, TRUE, TRUE, 0);
01265     gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 0, 12, 0);
01266 
01267     filepopup_settings_recurse_for_cover = gtk_check_button_new_with_mnemonic(_("Recursively search for cover"));
01268     gtk_container_add(GTK_CONTAINER(alignment), filepopup_settings_recurse_for_cover);
01269 
01270     alignment = gtk_alignment_new(0.5, 0.5, 1, 1);
01271     gtk_box_pack_start(GTK_BOX(vbox), alignment, FALSE, FALSE, 0);
01272     gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 0, 45, 0);
01273 
01274     filepopup_settings_recurse_for_cover_depth_box = gtk_hbox_new(FALSE, 0);
01275     gtk_container_add(GTK_CONTAINER(alignment), filepopup_settings_recurse_for_cover_depth_box);
01276 
01277     label_search_depth = gtk_label_new(_("Search depth: "));
01278     gtk_box_pack_start(GTK_BOX(filepopup_settings_recurse_for_cover_depth_box), label_search_depth, TRUE, TRUE, 0);
01279     gtk_misc_set_padding(GTK_MISC(label_search_depth), 4, 0);
01280 
01281     recurse_for_cover_depth_adj = gtk_adjustment_new(0, 0, 100, 1, 10, 0);
01282     filepopup_settings_recurse_for_cover_depth = gtk_spin_button_new(GTK_ADJUSTMENT(recurse_for_cover_depth_adj), 1, 0);
01283     gtk_box_pack_start(GTK_BOX(filepopup_settings_recurse_for_cover_depth_box), filepopup_settings_recurse_for_cover_depth, TRUE, TRUE, 0);
01284     gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(filepopup_settings_recurse_for_cover_depth), TRUE);
01285 
01286     alignment = gtk_alignment_new(0.5, 0.5, 1, 1);
01287     gtk_box_pack_start(GTK_BOX(vbox), alignment, TRUE, TRUE, 0);
01288     gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 0, 12, 0);
01289 
01290     filepopup_settings_use_file_cover = gtk_check_button_new_with_mnemonic(_("Use per-file cover"));
01291     gtk_container_add(GTK_CONTAINER(alignment), filepopup_settings_use_file_cover);
01292 
01293     label_misc = gtk_label_new(_("<b>Miscellaneous</b>"));
01294     gtk_box_pack_start(GTK_BOX(vbox), label_misc, FALSE, FALSE, 0);
01295     gtk_label_set_use_markup(GTK_LABEL(label_misc), TRUE);
01296     gtk_misc_set_alignment(GTK_MISC(label_misc), 0, 0.5);
01297 
01298     alignment = gtk_alignment_new(0.5, 0.5, 1, 1);
01299     gtk_box_pack_start(GTK_BOX(vbox), alignment, FALSE, FALSE, 0);
01300     gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 0, 12, 0);
01301 
01302     filepopup_settings_showprogressbar = gtk_check_button_new_with_mnemonic(_("Show Progress bar for the current track"));
01303     gtk_container_add(GTK_CONTAINER(alignment), filepopup_settings_showprogressbar);
01304 
01305     alignment = gtk_alignment_new(0, 0.5, 1, 1);
01306     gtk_box_pack_start(GTK_BOX(vbox), alignment, TRUE, TRUE, 0);
01307     gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 0, 12, 0);
01308 
01309     hbox = gtk_hbox_new(FALSE, 0);
01310     gtk_container_add(GTK_CONTAINER(alignment), hbox);
01311 
01312     label_delay = gtk_label_new(_("Delay until filepopup comes up: "));
01313     gtk_box_pack_start(GTK_BOX(hbox), label_delay, TRUE, TRUE, 0);
01314     gtk_misc_set_alignment(GTK_MISC(label_delay), 0, 0.5);
01315     gtk_misc_set_padding(GTK_MISC(label_delay), 12, 0);
01316 
01317     delay_adj = gtk_adjustment_new(0, 0, 100, 1, 10, 0);
01318     filepopup_settings_delay = gtk_spin_button_new(GTK_ADJUSTMENT(delay_adj), 1, 0);
01319     gtk_box_pack_start(GTK_BOX(hbox), filepopup_settings_delay, TRUE, TRUE, 0);
01320     gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(filepopup_settings_delay), TRUE);
01321 
01322     hbuttonbox = gtk_hbutton_box_new();
01323     gtk_box_pack_start(GTK_BOX(vbox), hbuttonbox, FALSE, FALSE, 0);
01324     gtk_button_box_set_layout(GTK_BUTTON_BOX(hbuttonbox), GTK_BUTTONBOX_END);
01325     gtk_box_set_spacing(GTK_BOX(hbuttonbox), 6);
01326 
01327     btn_cancel = gtk_button_new_from_stock("gtk-cancel");
01328     gtk_container_add(GTK_CONTAINER(hbuttonbox), btn_cancel);
01329 
01330     btn_ok = gtk_button_new_from_stock("gtk-ok");
01331     gtk_container_add(GTK_CONTAINER(hbuttonbox), btn_ok);
01332     gtk_widget_set_can_default(btn_ok, TRUE);
01333 
01334     g_signal_connect(G_OBJECT(filepopup_settings), "delete_event",
01335                      G_CALLBACK(gtk_widget_hide_on_delete),
01336                      NULL);
01337     g_signal_connect(G_OBJECT(btn_cancel), "clicked",
01338                      G_CALLBACK(on_filepopup_settings_cancel_clicked),
01339                      NULL);
01340     g_signal_connect(G_OBJECT(btn_ok), "clicked",
01341                      G_CALLBACK(on_filepopup_settings_ok_clicked),
01342                      NULL);
01343     g_signal_connect(G_OBJECT(filepopup_settings_recurse_for_cover), "toggled",
01344                      G_CALLBACK(on_recurse_for_cover_toggled),
01345                      filepopup_settings_recurse_for_cover_depth_box);
01346 
01347     gtk_widget_grab_default(btn_ok);
01348     gtk_widget_show_all(vbox);
01349 }
01350 
01351 static void create_spin_button (PreferencesWidget * widget, GtkWidget * *
01352  label_pre, GtkWidget * * spin_btn, GtkWidget * * label_past, const gchar *
01353  domain)
01354 {
01355      g_return_if_fail(widget->type == WIDGET_SPIN_BTN);
01356 
01357      * label_pre = gtk_label_new (dgettext (domain, widget->label));
01358      gtk_misc_set_alignment(GTK_MISC(*label_pre), 0, 0.5);
01359      gtk_misc_set_padding(GTK_MISC(*label_pre), 4, 0);
01360 
01361      *spin_btn = gtk_spin_button_new_with_range(widget->data.spin_btn.min,
01362                                                 widget->data.spin_btn.max,
01363                                                 widget->data.spin_btn.step);
01364 
01365 
01366      if (widget->tooltip)
01367          gtk_widget_set_tooltip_text (* spin_btn, dgettext (domain,
01368           widget->tooltip));
01369 
01370      if (widget->data.spin_btn.right_label) {
01371          * label_past = gtk_label_new (dgettext (domain,
01372           widget->data.spin_btn.right_label));
01373          gtk_misc_set_alignment(GTK_MISC(*label_past), 0, 0.5);
01374          gtk_misc_set_padding(GTK_MISC(*label_past), 4, 0);
01375      }
01376 
01377      switch (widget->cfg_type) {
01378          case VALUE_INT:
01379              g_signal_connect(G_OBJECT(*spin_btn), "value_changed",
01380                               G_CALLBACK(on_spin_btn_changed_gint),
01381                               widget->cfg);
01382              g_signal_connect(G_OBJECT(*spin_btn), "realize",
01383                               G_CALLBACK(on_spin_btn_realize_gint),
01384                               widget->cfg);
01385              break;
01386          case VALUE_FLOAT:
01387              g_signal_connect(G_OBJECT(*spin_btn), "value_changed",
01388                               G_CALLBACK(on_spin_btn_changed_gfloat),
01389                               widget->cfg);
01390              g_signal_connect(G_OBJECT(*spin_btn), "realize",
01391                               G_CALLBACK(on_spin_btn_realize_gfloat),
01392                               widget->cfg);
01393              break;
01394          case VALUE_NULL:
01395              break;
01396          default:
01397              g_warning("Unsupported value type for spin button");
01398      }
01399 }
01400 
01401 void create_font_btn (PreferencesWidget * widget, GtkWidget * * label,
01402  GtkWidget * * font_btn, const gchar * domain)
01403 {
01404     *font_btn = gtk_font_button_new();
01405     gtk_font_button_set_use_font(GTK_FONT_BUTTON(*font_btn), TRUE);
01406     gtk_font_button_set_use_size(GTK_FONT_BUTTON(*font_btn), TRUE);
01407     if (widget->label) {
01408         * label = gtk_label_new_with_mnemonic (dgettext (domain, widget->label));
01409         gtk_label_set_use_markup(GTK_LABEL(*label), TRUE);
01410         gtk_misc_set_alignment(GTK_MISC(*label), 1, 0.5);
01411         gtk_label_set_justify(GTK_LABEL(*label), GTK_JUSTIFY_RIGHT);
01412         gtk_label_set_mnemonic_widget(GTK_LABEL(*label), *font_btn);
01413     }
01414 
01415     if (widget->data.font_btn.title)
01416         gtk_font_button_set_title (GTK_FONT_BUTTON (* font_btn),
01417          dgettext (domain, widget->data.font_btn.title));
01418 
01419     g_object_set_data ((GObject *) (* font_btn), "callback", (void *)
01420      widget->callback);
01421 
01422     g_signal_connect(G_OBJECT(*font_btn), "font_set",
01423                      G_CALLBACK(on_font_btn_font_set),
01424                      (gchar**)widget->cfg);
01425     g_signal_connect(G_OBJECT(*font_btn), "realize",
01426                      G_CALLBACK(on_font_btn_realize),
01427                      (gchar**)widget->cfg);
01428 }
01429 
01430 static void create_entry (PreferencesWidget * widget, GtkWidget * * label,
01431  GtkWidget * * entry, const gchar * domain)
01432 {
01433     *entry = gtk_entry_new();
01434     gtk_entry_set_visibility(GTK_ENTRY(*entry), !widget->data.entry.password);
01435 
01436     if (widget->label)
01437         * label = gtk_label_new (dgettext (domain, widget->label));
01438 
01439     if (widget->tooltip)
01440         gtk_widget_set_tooltip_text (* entry, dgettext (domain, widget->tooltip));
01441 
01442     g_object_set_data ((GObject *) (* entry), "callback", (void *)
01443      widget->callback);
01444 
01445     switch (widget->cfg_type) {
01446         case VALUE_STRING:
01447             g_signal_connect(G_OBJECT(*entry), "realize",
01448                              G_CALLBACK(on_entry_realize),
01449                              widget->cfg);
01450             g_signal_connect(G_OBJECT(*entry), "changed",
01451                              G_CALLBACK(on_entry_changed),
01452                              widget->cfg);
01453             break;
01454         case VALUE_CFG_STRING:
01455             g_signal_connect(G_OBJECT(*entry), "realize",
01456                              G_CALLBACK(on_entry_cfg_realize),
01457                              widget->cfg);
01458             g_signal_connect(G_OBJECT(*entry), "changed",
01459                              G_CALLBACK(on_entry_cfg_changed),
01460                              widget->cfg);
01461             break;
01462         default:
01463             g_warning("Unhandled entry value type %d", widget->cfg_type);
01464     }
01465 }
01466 
01467 static void create_label (PreferencesWidget * widget, GtkWidget * * label,
01468  GtkWidget * * icon, const gchar * domain)
01469 {
01470     if (widget->data.label.stock_id)
01471         *icon = gtk_image_new_from_stock(widget->data.label.stock_id, GTK_ICON_SIZE_BUTTON);
01472 
01473     * label = gtk_label_new_with_mnemonic (dgettext (domain, widget->label));
01474     gtk_label_set_use_markup(GTK_LABEL(*label), TRUE);
01475 
01476     if (widget->data.label.single_line == FALSE)
01477         gtk_label_set_line_wrap(GTK_LABEL(*label), TRUE);
01478 
01479     gtk_misc_set_alignment(GTK_MISC(*label), 0, 0.5);
01480 }
01481 
01482 static void create_cbox (PreferencesWidget * widget, GtkWidget * * label,
01483  GtkWidget * * combobox, const gchar * domain)
01484 {
01485     *combobox = gtk_combo_box_new_text();
01486 
01487     if (widget->label) {
01488         * label = gtk_label_new (dgettext (domain, widget->label));
01489         gtk_misc_set_alignment(GTK_MISC(*label), 1, 0.5);
01490     }
01491 
01492     g_signal_connect_after(G_OBJECT(*combobox), "realize",
01493                            G_CALLBACK(on_cbox_realize),
01494                            widget);
01495 }
01496 
01497 static void fill_table (GtkWidget * table, PreferencesWidget * elements, gint
01498  amt, const gchar * domain)
01499 {
01500     gint x;
01501     GtkWidget *widget_left, *widget_middle, *widget_right;
01502     GtkAttachOptions middle_policy = (GtkAttachOptions) (0);
01503 
01504     for (x = 0; x < amt; ++x) {
01505         widget_left = widget_middle = widget_right = NULL;
01506         switch (elements[x].type) {
01507             case WIDGET_SPIN_BTN:
01508                 create_spin_button (& elements[x], & widget_left,
01509                  & widget_middle, & widget_right, domain);
01510                 middle_policy = (GtkAttachOptions) (GTK_FILL);
01511                 break;
01512             case WIDGET_LABEL:
01513                 create_label (& elements[x], & widget_middle, & widget_left,
01514                  domain);
01515                 middle_policy = (GtkAttachOptions) (GTK_FILL);
01516                 break;
01517             case WIDGET_FONT_BTN:
01518                 create_font_btn (& elements[x], & widget_left, & widget_middle,
01519                  domain);
01520                 middle_policy = (GtkAttachOptions) (GTK_EXPAND | GTK_FILL);
01521                 break;
01522             case WIDGET_ENTRY:
01523                 create_entry (& elements[x], & widget_left, & widget_middle,
01524                  domain);
01525                 middle_policy = (GtkAttachOptions) (GTK_EXPAND | GTK_FILL);
01526                 break;
01527             case WIDGET_COMBO_BOX:
01528                 create_cbox (& elements[x], & widget_left, & widget_middle,
01529                  domain);
01530                 middle_policy = (GtkAttachOptions) (GTK_EXPAND | GTK_FILL);
01531                 break;
01532             default:
01533                 g_warning("Unsupported widget type %d in table", elements[x].type);
01534         }
01535 
01536         if (widget_left)
01537             gtk_table_attach(GTK_TABLE (table), widget_left, 0, 1, x, x+1,
01538                              (GtkAttachOptions) (0),
01539                              (GtkAttachOptions) (0), 0, 0);
01540 
01541         if (widget_middle)
01542             gtk_table_attach(GTK_TABLE(table), widget_middle, 1, widget_right ? 2 : 3, x, x+1,
01543                              middle_policy,
01544                              (GtkAttachOptions) (0), 4, 0);
01545 
01546         if (widget_right)
01547             gtk_table_attach(GTK_TABLE(table), widget_right, 2, 3, x, x+1,
01548                              (GtkAttachOptions) (0),
01549                              (GtkAttachOptions) (0), 0, 0);
01550     }
01551 }
01552 
01553 /* void create_widgets_with_domain (GtkBox * box, PreferencesWidget * widgets,
01554  gint amt, const gchar * domain) */
01555 void create_widgets_with_domain (void * box, PreferencesWidget * widgets, gint
01556  amt, const gchar * domain)
01557 {
01558     gint x;
01559     GtkWidget *alignment = NULL, *widget = NULL;
01560     GtkWidget *child_box = NULL;
01561     GSList *radio_btn_group = NULL;
01562 
01563     for (x = 0; x < amt; ++x) {
01564         if (widgets[x].child) { /* perhaps this logic can be better */
01565             if (!child_box) {
01566                 child_box = gtk_vbox_new(FALSE, 0);
01567                 g_object_set_data(G_OBJECT(widget), "child", child_box);
01568                 alignment = gtk_alignment_new (0.5, 0.5, 1, 1);
01569                 gtk_box_pack_start(box, alignment, FALSE, FALSE, 0);
01570                 gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 0, 0, 24, 0);
01571                 gtk_container_add (GTK_CONTAINER (alignment), child_box);
01572             }
01573         } else
01574             child_box = NULL;
01575 
01576         alignment = gtk_alignment_new (0.5, 0.5, 1, 1);
01577         gtk_box_pack_start(child_box ? GTK_BOX(child_box) : box, alignment, FALSE, FALSE, 0);
01578 
01579         if (radio_btn_group && widgets[x].type != WIDGET_RADIO_BTN)
01580             radio_btn_group = NULL;
01581 
01582         switch(widgets[x].type) {
01583             case WIDGET_CHK_BTN:
01584                 gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 0, 12, 0);
01585                 widget = gtk_check_button_new_with_mnemonic (dgettext (domain,
01586                  widgets[x].label));
01587                 g_object_set_data ((GObject *) widget, "callback",
01588                  (void *) widgets[x].callback);
01589 
01590                 if (widgets[x].cfg_type == VALUE_CFG_BOOLEAN) {
01591                     g_signal_connect(G_OBJECT(widget), "toggled",
01592                                      G_CALLBACK(on_toggle_button_cfg_toggled),
01593                                      widgets[x].cfg);
01594                     g_signal_connect(G_OBJECT(widget), "realize",
01595                                      G_CALLBACK(on_toggle_button_cfg_realize),
01596                                      widgets[x].cfg);
01597                 } else {
01598                     if (widgets[x].cfg) {
01599                         g_signal_connect(G_OBJECT(widget), "toggled",
01600                                          G_CALLBACK(on_toggle_button_toggled),
01601                                          widgets[x].cfg);
01602                     } else {
01603                         gtk_widget_set_sensitive(widget, FALSE);
01604                     }
01605                     g_signal_connect(G_OBJECT(widget), "realize",
01606                                      G_CALLBACK(on_toggle_button_realize),
01607                                      widgets[x].cfg);
01608                 }
01609                 break;
01610             case WIDGET_LABEL:
01611                 gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 12, 6, 0, 0);
01612 
01613                 GtkWidget *label = NULL, *icon = NULL;
01614                 create_label (& widgets[x], & label, & icon, domain);
01615 
01616                 if (icon == NULL)
01617                     widget = label;
01618                 else {
01619                     widget = gtk_hbox_new(FALSE, 6);
01620                     gtk_box_pack_start(GTK_BOX(widget), icon, FALSE, FALSE, 0);
01621                     gtk_box_pack_start(GTK_BOX(widget), label, FALSE, FALSE, 0);
01622                 }
01623                 break;
01624             case WIDGET_RADIO_BTN:
01625                 gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 0, 12, 0);
01626                 widget = gtk_radio_button_new_with_mnemonic (radio_btn_group,
01627                  dgettext (domain, widgets[x].label));
01628                 radio_btn_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (widget));
01629                 g_signal_connect(G_OBJECT(widget), "toggled",
01630                                  G_CALLBACK(on_toggle_button_toggled),
01631                                  widgets[x].cfg);
01632                 g_signal_connect(G_OBJECT(widget), "realize",
01633                                  G_CALLBACK(on_toggle_button_realize),
01634                                  widgets[x].cfg);
01635                 break;
01636             case WIDGET_SPIN_BTN:
01637                 gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 6, 0, 12, 0);
01638 
01639                 widget = gtk_hbox_new(FALSE, 6);
01640 
01641                 GtkWidget *label_pre = NULL, *spin_btn = NULL, *label_past = NULL;
01642                 create_spin_button (& widgets[x], & label_pre, & spin_btn,
01643                  & label_past, domain);
01644 
01645                 if (label_pre)
01646                     gtk_box_pack_start(GTK_BOX(widget), label_pre, FALSE, FALSE, 0);
01647                 if (spin_btn)
01648                     gtk_box_pack_start(GTK_BOX(widget), spin_btn, FALSE, FALSE, 0);
01649                 if (label_past)
01650                     gtk_box_pack_start(GTK_BOX(widget), label_past, FALSE, FALSE, 0);
01651 
01652                 break;
01653             case WIDGET_CUSTOM:  /* custom widget. --nenolod */
01654                 if (widgets[x].data.populate)
01655                     widget = widgets[x].data.populate();
01656                 else
01657                     widget = NULL;
01658 
01659                 break;
01660             case WIDGET_FONT_BTN:
01661                 gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 0, 0, 12, 0);
01662 
01663                 widget = gtk_hbox_new(FALSE, 6);
01664 
01665                 GtkWidget *font_btn = NULL;
01666                 create_font_btn (& widgets[x], & label, & font_btn, domain);
01667 
01668                 if (label)
01669                     gtk_box_pack_start(GTK_BOX(widget), label, FALSE, FALSE, 0);
01670                 if (font_btn)
01671                     gtk_box_pack_start(GTK_BOX(widget), font_btn, FALSE, FALSE, 0);
01672                 break;
01673             case WIDGET_TABLE:
01674                 gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 0, 0, 12, 0);
01675 
01676                 widget = gtk_table_new(widgets[x].data.table.rows, 3, FALSE);
01677                 fill_table (widget, widgets[x].data.table.elem,
01678                  widgets[x].data.table.rows, domain);
01679                 gtk_table_set_row_spacings(GTK_TABLE(widget), 6);
01680                 break;
01681             case WIDGET_ENTRY:
01682                 gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 6, 0, 6, 12);
01683 
01684                 widget = gtk_hbox_new(FALSE, 6);
01685 
01686                 GtkWidget *entry = NULL;
01687                 create_entry (& widgets[x], & label, & entry, domain);
01688 
01689                 if (label)
01690                     gtk_box_pack_start(GTK_BOX(widget), label, FALSE, FALSE, 0);
01691                 if (entry)
01692                     gtk_box_pack_start(GTK_BOX(widget), entry, TRUE, TRUE, 0);
01693                 break;
01694             case WIDGET_COMBO_BOX:
01695                 gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 0, 0, 12, 0);
01696 
01697                 widget = gtk_hbox_new(FALSE, 10);
01698 
01699                 GtkWidget *combo = NULL;
01700                 create_cbox (& widgets[x], & label, & combo, domain);
01701 
01702                 if (label)
01703                     gtk_box_pack_start(GTK_BOX(widget), label, FALSE, FALSE, 0);
01704                 if (combo)
01705                     gtk_box_pack_start(GTK_BOX(widget), combo, FALSE, FALSE, 0);
01706                 break;
01707             case WIDGET_BOX:
01708                 gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 0, 0, 3, 0);
01709 
01710                 if (widgets[x].data.box.horizontal) {
01711                     widget = gtk_hbox_new(FALSE, 0);
01712                 } else {
01713                     widget = gtk_vbox_new(FALSE, 0);
01714                 }
01715 
01716                 create_widgets(GTK_BOX(widget), widgets[x].data.box.elem, widgets[x].data.box.n_elem);
01717 
01718                 if (widgets[x].data.box.frame) {
01719                     GtkWidget *tmp;
01720                     tmp = widget;
01721 
01722                     widget = gtk_frame_new (dgettext (domain, widgets[x].label));
01723                     gtk_container_add(GTK_CONTAINER(widget), tmp);
01724                 }
01725                 break;
01726             case WIDGET_NOTEBOOK:
01727                 gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 0, 0, 3, 0);
01728 
01729                 widget = gtk_notebook_new();
01730 
01731                 gint i;
01732                 for (i = 0; i<widgets[x].data.notebook.n_tabs; i++) {
01733                     GtkWidget *vbox;
01734                     vbox = gtk_vbox_new(FALSE, 5);
01735                     create_widgets(GTK_BOX(vbox), widgets[x].data.notebook.tabs[i].settings, widgets[x].data.notebook.tabs[i].n_settings);
01736 
01737                     gtk_notebook_append_page (GTK_NOTEBOOK (widget), vbox,
01738                      gtk_label_new (dgettext (domain,
01739                      widgets[x].data.notebook.tabs[i].name)));
01740                 }
01741                 break;
01742             case WIDGET_SEPARATOR:
01743                 gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 6, 6, 0, 0);
01744 
01745                 if (widgets[x].data.separator.horizontal == TRUE) {
01746                     widget = gtk_hseparator_new();
01747                 } else {
01748                     widget = gtk_vseparator_new();
01749                 }
01750                 break;
01751             default:
01752                 /* shouldn't ever happen - expect things to break */
01753                 g_error("This shouldn't ever happen - expect things to break.");
01754                 continue;
01755         }
01756 
01757         if (widget && !gtk_widget_get_parent(widget))
01758             gtk_container_add(GTK_CONTAINER(alignment), widget);
01759         if (widget && widgets[x].tooltip && widgets[x].type != WIDGET_SPIN_BTN)
01760             gtk_widget_set_tooltip_text (widget, dgettext (domain,
01761              widgets[x].tooltip));
01762     }
01763 
01764 }
01765 
01766 static GtkWidget *
01767 create_titlestring_tag_menu(void)
01768 {
01769     GtkWidget *titlestring_tag_menu, *menu_item;
01770     guint i;
01771 
01772     titlestring_tag_menu = gtk_menu_new();
01773     for(i = 0; i < n_title_field_tags; i++) {
01774         menu_item = gtk_menu_item_new_with_label(_(title_field_tags[i].name));
01775         gtk_menu_shell_append(GTK_MENU_SHELL(titlestring_tag_menu), menu_item);
01776         g_signal_connect(menu_item, "activate",
01777                          G_CALLBACK(titlestring_tag_menu_callback),
01778                          GINT_TO_POINTER(i));
01779     };
01780     gtk_widget_show_all(titlestring_tag_menu);
01781 
01782     return titlestring_tag_menu;
01783 }
01784 
01785 static void
01786 create_playback_category(void)
01787 {
01788     GtkWidget *playback_page_vbox;
01789     GtkWidget *widgets_vbox;
01790 
01791     playback_page_vbox = gtk_vbox_new (FALSE, 0);
01792     gtk_container_add (GTK_CONTAINER (category_notebook), playback_page_vbox);
01793 
01794     widgets_vbox = gtk_vbox_new (FALSE, 0);
01795     create_widgets(GTK_BOX(widgets_vbox), playback_page_widgets, G_N_ELEMENTS(playback_page_widgets));
01796     gtk_box_pack_start (GTK_BOX (playback_page_vbox), widgets_vbox, TRUE, TRUE, 0);
01797 }
01798 
01799 static void
01800 create_replay_gain_category(void)
01801 {
01802     GtkWidget *rg_page_vbox;
01803     GtkWidget *widgets_vbox;
01804 
01805     rg_page_vbox = gtk_vbox_new (FALSE, 0);
01806     gtk_container_add (GTK_CONTAINER (category_notebook), rg_page_vbox);
01807 
01808     widgets_vbox = gtk_vbox_new (FALSE, 0);
01809     create_widgets(GTK_BOX(widgets_vbox), replay_gain_page_widgets, G_N_ELEMENTS(replay_gain_page_widgets));
01810     gtk_box_pack_start (GTK_BOX (rg_page_vbox), widgets_vbox, TRUE, TRUE, 0);
01811 }
01812 
01813 static void show_numbers_cb (GtkToggleButton * numbers, void * unused)
01814 {
01815     cfg.show_numbers_in_pl = gtk_toggle_button_get_active (numbers);
01816 
01817     hook_call ("playlist update", NULL);
01818     hook_call ("title change", NULL);
01819 }
01820 
01821 static void
01822 create_playlist_category(void)
01823 {
01824     GtkWidget *playlist_page_vbox;
01825     GtkWidget *vbox5;
01826     GtkWidget *alignment55;
01827     GtkWidget *label60;
01828     GtkWidget *alignment56;
01829     GtkWidget *table6;
01830     GtkWidget *titlestring_help_button;
01831     GtkWidget *image1;
01832     GtkWidget *titlestring_cbox;
01833     GtkWidget *label62;
01834     GtkWidget *label61;
01835     GtkWidget *alignment85;
01836     GtkWidget *label84;
01837     GtkWidget *alignment86;
01838     GtkWidget *hbox9;
01839     GtkWidget *vbox34;
01840     GtkWidget *checkbutton10;
01841     GtkWidget *image8;
01842     GtkWidget *titlestring_tag_menu = create_titlestring_tag_menu();
01843     GtkWidget * numbers_alignment, * numbers;
01844 
01845     playlist_page_vbox = gtk_vbox_new (FALSE, 0);
01846     gtk_container_add (GTK_CONTAINER (category_notebook), playlist_page_vbox);
01847 
01848     vbox5 = gtk_vbox_new (FALSE, 0);
01849     gtk_box_pack_start (GTK_BOX (playlist_page_vbox), vbox5, TRUE, TRUE, 0);
01850 
01851     create_widgets(GTK_BOX(vbox5), playlist_page_widgets, G_N_ELEMENTS(playlist_page_widgets));
01852 
01853     alignment55 = gtk_alignment_new (0.5, 0.5, 1, 1);
01854     gtk_box_pack_start (GTK_BOX (vbox5), alignment55, FALSE, FALSE, 0);
01855     gtk_alignment_set_padding ((GtkAlignment *) alignment55, 12, 3, 0, 0);
01856 
01857     label60 = gtk_label_new (_("<b>Song Display</b>"));
01858     gtk_container_add (GTK_CONTAINER (alignment55), label60);
01859     gtk_label_set_use_markup (GTK_LABEL (label60), TRUE);
01860     gtk_misc_set_alignment (GTK_MISC (label60), 0, 0.5);
01861 
01862     numbers_alignment = gtk_alignment_new (0, 0, 0, 0);
01863     gtk_alignment_set_padding ((GtkAlignment *) numbers_alignment, 0, 0, 12, 0);
01864     gtk_box_pack_start ((GtkBox *) vbox5, numbers_alignment, 0, 0, 3);
01865 
01866     numbers = gtk_check_button_new_with_label (_("Show song numbers"));
01867     gtk_toggle_button_set_active ((GtkToggleButton *) numbers,
01868      cfg.show_numbers_in_pl);
01869     g_signal_connect ((GObject *) numbers, "toggled", (GCallback)
01870      show_numbers_cb, 0);
01871     gtk_container_add ((GtkContainer *) numbers_alignment, numbers);
01872 
01873     alignment56 = gtk_alignment_new (0.5, 0.5, 1, 1);
01874     gtk_box_pack_start (GTK_BOX (vbox5), alignment56, FALSE, FALSE, 0);
01875     gtk_alignment_set_padding (GTK_ALIGNMENT (alignment56), 0, 0, 12, 0);
01876 
01877     table6 = gtk_table_new (2, 3, FALSE);
01878     gtk_container_add (GTK_CONTAINER (alignment56), table6);
01879     gtk_table_set_row_spacings (GTK_TABLE (table6), 4);
01880     gtk_table_set_col_spacings (GTK_TABLE (table6), 12);
01881 
01882     titlestring_help_button = gtk_button_new ();
01883     gtk_table_attach (GTK_TABLE (table6), titlestring_help_button, 2, 3, 1, 2,
01884                       (GtkAttachOptions) (0),
01885                       (GtkAttachOptions) (0), 0, 0);
01886 
01887     gtk_widget_set_can_focus (titlestring_help_button, FALSE);
01888     gtk_widget_set_tooltip_text (titlestring_help_button, _("Show information about titlestring format"));
01889     gtk_button_set_relief (GTK_BUTTON (titlestring_help_button), GTK_RELIEF_HALF);
01890     gtk_button_set_focus_on_click (GTK_BUTTON (titlestring_help_button), FALSE);
01891 
01892     image1 = gtk_image_new_from_stock ("gtk-index", GTK_ICON_SIZE_BUTTON);
01893     gtk_container_add (GTK_CONTAINER (titlestring_help_button), image1);
01894 
01895     titlestring_cbox = gtk_combo_box_new_text ();
01896     gtk_table_attach (GTK_TABLE (table6), titlestring_cbox, 1, 3, 0, 1,
01897                       (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
01898                       (GtkAttachOptions) (0), 0, 0);
01899     gtk_combo_box_append_text (GTK_COMBO_BOX (titlestring_cbox), _("TITLE"));
01900     gtk_combo_box_append_text (GTK_COMBO_BOX (titlestring_cbox), _("ARTIST - TITLE"));
01901     gtk_combo_box_append_text (GTK_COMBO_BOX (titlestring_cbox), _("ARTIST - ALBUM - TITLE"));
01902     gtk_combo_box_append_text (GTK_COMBO_BOX (titlestring_cbox), _("ARTIST - ALBUM - TRACK. TITLE"));
01903     gtk_combo_box_append_text (GTK_COMBO_BOX (titlestring_cbox), _("ARTIST [ ALBUM ] - TRACK. TITLE"));
01904     gtk_combo_box_append_text (GTK_COMBO_BOX (titlestring_cbox), _("ALBUM - TITLE"));
01905     gtk_combo_box_append_text (GTK_COMBO_BOX (titlestring_cbox), _("Custom"));
01906 
01907     titlestring_entry = gtk_entry_new ();
01908     gtk_table_attach (GTK_TABLE (table6), titlestring_entry, 1, 2, 1, 2,
01909                       (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
01910                       (GtkAttachOptions) (0), 0, 0);
01911 
01912     label62 = gtk_label_new (_("Custom string:"));
01913     gtk_table_attach (GTK_TABLE (table6), label62, 0, 1, 1, 2,
01914                       (GtkAttachOptions) (0),
01915                       (GtkAttachOptions) (0), 0, 0);
01916     gtk_label_set_justify (GTK_LABEL (label62), GTK_JUSTIFY_RIGHT);
01917     gtk_misc_set_alignment (GTK_MISC (label62), 1, 0.5);
01918 
01919     label61 = gtk_label_new (_("Title format:"));
01920     gtk_table_attach (GTK_TABLE (table6), label61, 0, 1, 0, 1,
01921                       (GtkAttachOptions) (0),
01922                       (GtkAttachOptions) (0), 0, 0);
01923     gtk_label_set_justify (GTK_LABEL (label61), GTK_JUSTIFY_RIGHT);
01924     gtk_misc_set_alignment (GTK_MISC (label61), 1, 0.5);
01925 
01926     alignment85 = gtk_alignment_new (0.5, 0.5, 1, 1);
01927     gtk_box_pack_start (GTK_BOX (vbox5), alignment85, FALSE, FALSE, 0);
01928     gtk_alignment_set_padding (GTK_ALIGNMENT (alignment85), 12, 12, 0, 0);
01929 
01930     label84 = gtk_label_new (_("<b>Popup Information</b>"));
01931     gtk_container_add (GTK_CONTAINER (alignment85), label84);
01932     gtk_label_set_use_markup (GTK_LABEL (label84), TRUE);
01933     gtk_misc_set_alignment (GTK_MISC (label84), 0, 0.5);
01934 
01935     alignment86 = gtk_alignment_new (0.5, 0.5, 1, 1);
01936     gtk_box_pack_start (GTK_BOX (vbox5), alignment86, FALSE, FALSE, 0);
01937     gtk_alignment_set_padding (GTK_ALIGNMENT (alignment86), 0, 0, 12, 0);
01938 
01939     hbox9 = gtk_hbox_new (FALSE, 12);
01940     gtk_container_add (GTK_CONTAINER (alignment86), hbox9);
01941 
01942     vbox34 = gtk_vbox_new (FALSE, 0);
01943     gtk_box_pack_start (GTK_BOX (hbox9), vbox34, TRUE, TRUE, 0);
01944 
01945     checkbutton10 = gtk_check_button_new_with_mnemonic (_("Show popup information for playlist entries"));
01946     gtk_box_pack_start (GTK_BOX (vbox34), checkbutton10, TRUE, FALSE, 0);
01947     gtk_widget_set_tooltip_text (checkbutton10, _("Toggles popup information window for the pointed entry in the playlist. The window shows title of song, name of album, genre, year of publish, track number, track length, and artwork."));
01948 
01949     filepopup_for_tuple_settings_button = gtk_button_new ();
01950     gtk_box_pack_start (GTK_BOX (hbox9), filepopup_for_tuple_settings_button, FALSE, FALSE, 0);
01951 
01952     gtk_widget_set_can_focus (filepopup_for_tuple_settings_button, FALSE);
01953     gtk_widget_set_tooltip_text (filepopup_for_tuple_settings_button, _("Edit settings for popup information"));
01954     gtk_button_set_relief (GTK_BUTTON (filepopup_for_tuple_settings_button), GTK_RELIEF_HALF);
01955 
01956     image8 = gtk_image_new_from_stock ("gtk-properties", GTK_ICON_SIZE_BUTTON);
01957     gtk_container_add (GTK_CONTAINER (filepopup_for_tuple_settings_button), image8);
01958 
01959 
01960 
01961     g_signal_connect(G_OBJECT(checkbutton10), "toggled",
01962                      G_CALLBACK(on_show_filepopup_for_tuple_toggled),
01963                      NULL);
01964     g_signal_connect_after(G_OBJECT(checkbutton10), "realize",
01965                            G_CALLBACK(on_show_filepopup_for_tuple_realize),
01966                            NULL);
01967     g_signal_connect(G_OBJECT(filepopup_for_tuple_settings_button), "clicked",
01968                      G_CALLBACK(on_filepopup_for_tuple_settings_clicked),
01969                      NULL);
01970 
01971     g_signal_connect(titlestring_cbox, "realize",
01972                      G_CALLBACK(on_titlestring_cbox_realize),
01973                      titlestring_entry);
01974     g_signal_connect(titlestring_cbox, "changed",
01975                      G_CALLBACK(on_titlestring_cbox_changed),
01976                      titlestring_entry);
01977 
01978     g_signal_connect(titlestring_cbox, "changed",
01979                      G_CALLBACK(on_titlestring_cbox_changed),
01980                      titlestring_help_button);
01981     g_signal_connect(titlestring_help_button, "clicked",
01982                      G_CALLBACK(on_titlestring_help_button_clicked),
01983                      titlestring_tag_menu);
01984 
01985     g_signal_connect(G_OBJECT(titlestring_entry), "changed",
01986                      G_CALLBACK(on_titlestring_entry_changed),
01987                      NULL);
01988     g_signal_connect_after(G_OBJECT(titlestring_entry), "realize",
01989                            G_CALLBACK(on_titlestring_entry_realize),
01990                            NULL);
01991 
01992 
01993 
01994     /* Create window for filepopup settings */
01995     create_filepopup_settings();
01996 }
01997 
01998 
01999 static void
02000 create_audio_category(void)
02001 {
02002     GtkWidget *audio_page_vbox;
02003     GtkWidget *alignment74;
02004     GtkWidget *label77;
02005     GtkWidget *alignment73;
02006     GtkWidget *vbox33;
02007     GtkWidget *table11;
02008     GtkWidget *label79;
02009     GtkObject *output_plugin_bufsize_adj;
02010     GtkWidget *output_plugin_bufsize;
02011     GtkWidget *output_plugin_cbox;
02012     GtkWidget *label78;
02013     GtkWidget *alignment82;
02014     GtkWidget *output_plugin_button_box;
02015     GtkWidget *output_plugin_prefs;
02016     GtkWidget *alignment76;
02017     GtkWidget *hbox7;
02018     GtkWidget *image5;
02019     GtkWidget *label80;
02020     GtkWidget *output_plugin_info;
02021     GtkWidget *alignment77;
02022     GtkWidget *hbox8;
02023     GtkWidget *image6;
02024     GtkWidget *label81;
02025 
02026     audio_page_vbox = gtk_vbox_new (FALSE, 0);
02027     gtk_container_add (GTK_CONTAINER (category_notebook), audio_page_vbox);
02028 
02029     alignment74 = gtk_alignment_new (0.5, 0.5, 1, 1);
02030     gtk_box_pack_start (GTK_BOX (audio_page_vbox), alignment74, FALSE, FALSE, 0);
02031     gtk_alignment_set_padding (GTK_ALIGNMENT (alignment74), 0, 12, 0, 0);
02032 
02033     label77 = gtk_label_new (_("<b>Audio System</b>"));
02034     gtk_container_add (GTK_CONTAINER (alignment74), label77);
02035     gtk_label_set_use_markup (GTK_LABEL (label77), TRUE);
02036     gtk_misc_set_alignment (GTK_MISC (label77), 0, 0.5);
02037 
02038     alignment73 = gtk_alignment_new (0.5, 0.5, 1, 1);
02039     gtk_box_pack_start (GTK_BOX (audio_page_vbox), alignment73, FALSE, FALSE, 0);
02040     gtk_alignment_set_padding (GTK_ALIGNMENT (alignment73), 0, 6, 12, 0);
02041 
02042     vbox33 = gtk_vbox_new (FALSE, 0);
02043     gtk_container_add (GTK_CONTAINER (alignment73), vbox33);
02044 
02045     table11 = gtk_table_new (3, 2, FALSE);
02046     gtk_box_pack_start (GTK_BOX (vbox33), table11, FALSE, FALSE, 0);
02047     gtk_table_set_row_spacings (GTK_TABLE (table11), 6);
02048     gtk_table_set_col_spacings (GTK_TABLE (table11), 6);
02049 
02050     label79 = gtk_label_new (_("Buffer size:"));
02051     gtk_table_attach (GTK_TABLE (table11), label79, 0, 1, 1, 2,
02052                       (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
02053                       (GtkAttachOptions) (0), 0, 0);
02054     gtk_misc_set_alignment (GTK_MISC (label79), 1, 0.5);
02055 
02056     output_plugin_bufsize_adj =
02057         gtk_adjustment_new (0, 100, 10000, 100, 1000, 0);
02058     output_plugin_bufsize = gtk_spin_button_new (GTK_ADJUSTMENT (output_plugin_bufsize_adj), 100, 0);
02059     gtk_table_attach (GTK_TABLE (table11), output_plugin_bufsize, 1, 2, 1, 2,
02060                       (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
02061                       (GtkAttachOptions) (0), 0, 0);
02062 
02063     output_plugin_cbox = gtk_combo_box_new_text ();
02064     gtk_table_attach (GTK_TABLE (table11), output_plugin_cbox, 1, 2, 0, 1,
02065                       (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
02066                       (GtkAttachOptions) (0), 0, 0);
02067 
02068     label78 = gtk_label_new (_("Current output plugin:"));
02069     gtk_table_attach (GTK_TABLE (table11), label78, 0, 1, 0, 1,
02070                       (GtkAttachOptions) (0),
02071                       (GtkAttachOptions) (0), 0, 0);
02072     gtk_misc_set_alignment (GTK_MISC (label78), 0, 0.5);
02073 
02074     alignment82 = gtk_alignment_new (0.5, 0.5, 1, 1);
02075     gtk_box_pack_start (GTK_BOX (audio_page_vbox), alignment82, FALSE, FALSE, 0);
02076     gtk_alignment_set_padding (GTK_ALIGNMENT (alignment82), 0, 0, 12, 0);
02077 
02078     output_plugin_button_box = gtk_hbutton_box_new ();
02079     gtk_container_add (GTK_CONTAINER (alignment82), output_plugin_button_box);
02080     gtk_button_box_set_layout (GTK_BUTTON_BOX (output_plugin_button_box), GTK_BUTTONBOX_START);
02081     gtk_box_set_spacing (GTK_BOX (output_plugin_button_box), 8);
02082 
02083     output_plugin_prefs = gtk_button_new ();
02084     gtk_container_add (GTK_CONTAINER (output_plugin_button_box), output_plugin_prefs);
02085     gtk_widget_set_sensitive (output_plugin_prefs, FALSE);
02086     gtk_widget_set_can_default(output_plugin_prefs, TRUE);
02087 
02088     alignment76 = gtk_alignment_new (0.5, 0.5, 0, 0);
02089     gtk_container_add (GTK_CONTAINER (output_plugin_prefs), alignment76);
02090 
02091     hbox7 = gtk_hbox_new (FALSE, 2);
02092     gtk_container_add (GTK_CONTAINER (alignment76), hbox7);
02093 
02094     image5 = gtk_image_new_from_stock ("gtk-preferences", GTK_ICON_SIZE_BUTTON);
02095     gtk_box_pack_start (GTK_BOX (hbox7), image5, FALSE, FALSE, 0);
02096 
02097     label80 = gtk_label_new_with_mnemonic (_("Output Plugin Preferences"));
02098     gtk_box_pack_start (GTK_BOX (hbox7), label80, FALSE, FALSE, 0);
02099 
02100     output_plugin_info = gtk_button_new ();
02101     gtk_container_add (GTK_CONTAINER (output_plugin_button_box), output_plugin_info);
02102     gtk_widget_set_sensitive (output_plugin_info, FALSE);
02103     gtk_widget_set_can_default(output_plugin_info, TRUE);
02104 
02105     alignment77 = gtk_alignment_new (0.5, 0.5, 0, 0);
02106     gtk_container_add (GTK_CONTAINER (output_plugin_info), alignment77);
02107 
02108     hbox8 = gtk_hbox_new (FALSE, 2);
02109     gtk_container_add (GTK_CONTAINER (alignment77), hbox8);
02110 
02111     image6 = gtk_image_new_from_stock ("gtk-about", GTK_ICON_SIZE_BUTTON);
02112     gtk_box_pack_start (GTK_BOX (hbox8), image6, FALSE, FALSE, 0);
02113 
02114     label81 = gtk_label_new_with_mnemonic (_("Output Plugin Information"));
02115     gtk_box_pack_start (GTK_BOX (hbox8), label81, FALSE, FALSE, 0);
02116 
02117     create_widgets(GTK_BOX(audio_page_vbox), audio_page_widgets, G_N_ELEMENTS(audio_page_widgets));
02118 
02119     g_signal_connect(G_OBJECT(output_plugin_bufsize), "value_changed",
02120                      G_CALLBACK(on_output_plugin_bufsize_value_changed),
02121                      NULL);
02122     g_signal_connect_after(G_OBJECT(output_plugin_bufsize), "realize",
02123                            G_CALLBACK(on_output_plugin_bufsize_realize),
02124                            NULL);
02125     g_signal_connect_after(G_OBJECT(output_plugin_cbox), "realize",
02126                            G_CALLBACK(on_output_plugin_cbox_realize),
02127                            NULL);
02128 
02129     /* plugin->output page */
02130 
02131     g_signal_connect(G_OBJECT(output_plugin_cbox), "changed",
02132                      G_CALLBACK(output_plugin_enable_prefs),
02133                      output_plugin_prefs);
02134     g_signal_connect_swapped(G_OBJECT(output_plugin_prefs), "clicked",
02135                              G_CALLBACK(output_plugin_open_prefs),
02136                              output_plugin_cbox);
02137 
02138     g_signal_connect(G_OBJECT(output_plugin_cbox), "changed",
02139                      G_CALLBACK(output_plugin_enable_info),
02140                      output_plugin_info);
02141     g_signal_connect_swapped(G_OBJECT(output_plugin_info), "clicked",
02142                              G_CALLBACK(output_plugin_open_info),
02143                              output_plugin_cbox);
02144 
02145 }
02146 
02147 static void
02148 create_connectivity_category(void)
02149 {
02150     GtkWidget *connectivity_page_vbox;
02151     GtkWidget *vbox29;
02152 
02153     connectivity_page_vbox = gtk_vbox_new (FALSE, 0);
02154     gtk_container_add (GTK_CONTAINER (category_notebook), connectivity_page_vbox);
02155 
02156     vbox29 = gtk_vbox_new (FALSE, 0);
02157     gtk_box_pack_start (GTK_BOX (connectivity_page_vbox), vbox29, TRUE, TRUE, 0);
02158 
02159     create_widgets(GTK_BOX(vbox29), connectivity_page_widgets, G_N_ELEMENTS(connectivity_page_widgets));
02160 }
02161 
02162 static void
02163 create_plugin_category(void)
02164 {
02165     GtkWidget *plugin_page_vbox;
02166     GtkWidget *plugin_notebook;
02167     GtkWidget *plugin_input_vbox;
02168     GtkWidget *alignment43;
02169     GtkWidget *input_plugin_list_label;
02170     GtkWidget *scrolledwindow3;
02171     GtkWidget *input_plugin_view;
02172     GtkWidget *input_plugin_button_box;
02173     GtkWidget *input_plugin_prefs;
02174     GtkWidget *input_plugin_info;
02175     GtkWidget *plugin_input_label;
02176     GtkWidget *plugin_general_vbox;
02177     GtkWidget *alignment45;
02178     GtkWidget *label11;
02179     GtkWidget *scrolledwindow5;
02180     GtkWidget *general_plugin_view;
02181     GtkWidget *general_plugin_button_box;
02182     GtkWidget *general_plugin_prefs;
02183     GtkWidget *general_plugin_info;
02184     GtkWidget *plugin_general_label;
02185     GtkWidget *vbox21;
02186     GtkWidget *alignment46;
02187     GtkWidget *label53;
02188     GtkWidget *scrolledwindow7;
02189     GtkWidget *vis_plugin_view;
02190     GtkWidget *hbuttonbox6;
02191     GtkWidget *vis_plugin_prefs;
02192     GtkWidget *vis_plugin_info;
02193     GtkWidget *vis_label;
02194     GtkWidget *vbox25;
02195     GtkWidget *alignment58;
02196     GtkWidget *label64;
02197     GtkWidget *scrolledwindow9;
02198     GtkWidget *effect_plugin_view;
02199     GtkWidget *hbuttonbox9;
02200     GtkWidget *effect_plugin_prefs;
02201     GtkWidget *effect_plugin_info;
02202     GtkWidget *effects_label;
02203 
02204     plugin_page_vbox = gtk_vbox_new (FALSE, 0);
02205     gtk_container_add (GTK_CONTAINER (category_notebook), plugin_page_vbox);
02206 
02207     plugin_notebook = gtk_notebook_new ();
02208     gtk_box_pack_start (GTK_BOX (plugin_page_vbox), plugin_notebook, TRUE, TRUE, 0);
02209     gtk_notebook_set_show_border (GTK_NOTEBOOK (plugin_notebook), FALSE);
02210 
02211     plugin_input_vbox = gtk_vbox_new (FALSE, 0);
02212     gtk_container_add (GTK_CONTAINER (plugin_notebook), plugin_input_vbox);
02213     gtk_container_set_border_width (GTK_CONTAINER (plugin_input_vbox), 12);
02214 
02215     alignment43 = gtk_alignment_new (0.5, 0.5, 1, 1);
02216     gtk_box_pack_start (GTK_BOX (plugin_input_vbox), alignment43, FALSE, FALSE, 4);
02217     gtk_alignment_set_padding (GTK_ALIGNMENT (alignment43), 0, 6, 0, 0);
02218 
02219     input_plugin_list_label = gtk_label_new_with_mnemonic (_("_Decoder list:"));
02220     gtk_container_add (GTK_CONTAINER (alignment43), input_plugin_list_label);
02221     gtk_label_set_use_markup (GTK_LABEL (input_plugin_list_label), TRUE);
02222     gtk_misc_set_alignment (GTK_MISC (input_plugin_list_label), 0, 0.5);
02223 
02224     scrolledwindow3 = gtk_scrolled_window_new (NULL, NULL);
02225     gtk_box_pack_start (GTK_BOX (plugin_input_vbox), scrolledwindow3, TRUE, TRUE, 0);
02226     gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow3), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
02227     gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow3), GTK_SHADOW_IN);
02228 
02229     input_plugin_view = gtk_tree_view_new ();
02230     gtk_container_add (GTK_CONTAINER (scrolledwindow3), input_plugin_view);
02231     gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (input_plugin_view), TRUE);
02232     gtk_tree_view_set_reorderable (GTK_TREE_VIEW (input_plugin_view), TRUE);
02233 
02234     input_plugin_button_box = gtk_hbutton_box_new ();
02235     gtk_box_pack_start (GTK_BOX (plugin_input_vbox), input_plugin_button_box, FALSE, FALSE, 8);
02236     gtk_button_box_set_layout (GTK_BUTTON_BOX (input_plugin_button_box), GTK_BUTTONBOX_START);
02237     gtk_box_set_spacing (GTK_BOX (input_plugin_button_box), 8);
02238 
02239     input_plugin_prefs = gtk_button_new_from_stock ("gtk-preferences");
02240     gtk_container_add (GTK_CONTAINER (input_plugin_button_box), input_plugin_prefs);
02241     gtk_widget_set_sensitive (input_plugin_prefs, FALSE);
02242     gtk_widget_set_can_default(input_plugin_prefs, TRUE);
02243 
02244     input_plugin_info = gtk_button_new_from_stock ("gtk-dialog-info");
02245     gtk_container_add (GTK_CONTAINER (input_plugin_button_box), input_plugin_info);
02246     gtk_widget_set_sensitive (input_plugin_info, FALSE);
02247     gtk_widget_set_can_default(input_plugin_info, TRUE);
02248 
02249     plugin_input_label = gtk_label_new (_("<span size=\"medium\"><b>Decoders</b></span>"));
02250     gtk_notebook_set_tab_label (GTK_NOTEBOOK (plugin_notebook), gtk_notebook_get_nth_page (GTK_NOTEBOOK (plugin_notebook), 0), plugin_input_label);
02251     gtk_label_set_use_markup (GTK_LABEL (plugin_input_label), TRUE);
02252     gtk_misc_set_alignment (GTK_MISC (plugin_input_label), 0, 0);
02253 
02254     plugin_general_vbox = gtk_vbox_new (FALSE, 0);
02255     gtk_container_add (GTK_CONTAINER (plugin_notebook), plugin_general_vbox);
02256     gtk_container_set_border_width (GTK_CONTAINER (plugin_general_vbox), 12);
02257 
02258     alignment45 = gtk_alignment_new (0.5, 0.5, 1, 1);
02259     gtk_box_pack_start (GTK_BOX (plugin_general_vbox), alignment45, FALSE, FALSE, 4);
02260     gtk_alignment_set_padding (GTK_ALIGNMENT (alignment45), 0, 6, 0, 0);
02261 
02262     label11 = gtk_label_new_with_mnemonic (_("_General plugin list:"));
02263     gtk_container_add (GTK_CONTAINER (alignment45), label11);
02264     gtk_label_set_use_markup (GTK_LABEL (label11), TRUE);
02265     gtk_misc_set_alignment (GTK_MISC (label11), 0, 0.5);
02266 
02267     scrolledwindow5 = gtk_scrolled_window_new (NULL, NULL);
02268     gtk_box_pack_start (GTK_BOX (plugin_general_vbox), scrolledwindow5, TRUE, TRUE, 0);
02269     gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow5), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
02270     gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow5), GTK_SHADOW_IN);
02271 
02272     general_plugin_view = gtk_tree_view_new ();
02273     gtk_container_add (GTK_CONTAINER (scrolledwindow5), general_plugin_view);
02274     gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (general_plugin_view), TRUE);
02275     gtk_tree_view_set_reorderable (GTK_TREE_VIEW (general_plugin_view), TRUE);
02276 
02277     general_plugin_button_box = gtk_hbutton_box_new ();
02278     gtk_box_pack_start (GTK_BOX (plugin_general_vbox), general_plugin_button_box, FALSE, FALSE, 8);
02279     gtk_button_box_set_layout (GTK_BUTTON_BOX (general_plugin_button_box), GTK_BUTTONBOX_START);
02280     gtk_box_set_spacing (GTK_BOX (general_plugin_button_box), 8);
02281 
02282     general_plugin_prefs = gtk_button_new_from_stock ("gtk-preferences");
02283     gtk_container_add (GTK_CONTAINER (general_plugin_button_box), general_plugin_prefs);
02284     gtk_widget_set_sensitive (general_plugin_prefs, FALSE);
02285     gtk_widget_set_can_default(general_plugin_prefs, TRUE);
02286 
02287     general_plugin_info = gtk_button_new_from_stock ("gtk-dialog-info");
02288     gtk_container_add (GTK_CONTAINER (general_plugin_button_box), general_plugin_info);
02289     gtk_widget_set_sensitive (general_plugin_info, FALSE);
02290     gtk_widget_set_can_default(general_plugin_info, TRUE);
02291 
02292     plugin_general_label = gtk_label_new (_("<span size=\"medium\"><b>General</b></span>"));
02293     gtk_notebook_set_tab_label (GTK_NOTEBOOK (plugin_notebook), gtk_notebook_get_nth_page (GTK_NOTEBOOK (plugin_notebook), 1), plugin_general_label);
02294     gtk_label_set_use_markup (GTK_LABEL (plugin_general_label), TRUE);
02295 
02296     vbox21 = gtk_vbox_new (FALSE, 0);
02297     gtk_container_add (GTK_CONTAINER (plugin_notebook), vbox21);
02298     gtk_container_set_border_width (GTK_CONTAINER (vbox21), 12);
02299 
02300     alignment46 = gtk_alignment_new (0.5, 0.5, 1, 1);
02301     gtk_box_pack_start (GTK_BOX (vbox21), alignment46, FALSE, FALSE, 4);
02302     gtk_alignment_set_padding (GTK_ALIGNMENT (alignment46), 0, 6, 0, 0);
02303 
02304     label53 = gtk_label_new_with_mnemonic (_("_Visualization plugin list:"));
02305     gtk_container_add (GTK_CONTAINER (alignment46), label53);
02306     gtk_label_set_use_markup (GTK_LABEL (label53), TRUE);
02307     gtk_misc_set_alignment (GTK_MISC (label53), 0, 0.5);
02308 
02309     scrolledwindow7 = gtk_scrolled_window_new (NULL, NULL);
02310     gtk_box_pack_start (GTK_BOX (vbox21), scrolledwindow7, TRUE, TRUE, 0);
02311     gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow7), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
02312     gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow7), GTK_SHADOW_IN);
02313 
02314     vis_plugin_view = gtk_tree_view_new ();
02315     gtk_container_add (GTK_CONTAINER (scrolledwindow7), vis_plugin_view);
02316     gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (vis_plugin_view), TRUE);
02317     gtk_tree_view_set_reorderable (GTK_TREE_VIEW (vis_plugin_view), TRUE);
02318 
02319     hbuttonbox6 = gtk_hbutton_box_new ();
02320     gtk_box_pack_start (GTK_BOX (vbox21), hbuttonbox6, FALSE, FALSE, 8);
02321     gtk_button_box_set_layout (GTK_BUTTON_BOX (hbuttonbox6), GTK_BUTTONBOX_START);
02322     gtk_box_set_spacing (GTK_BOX (hbuttonbox6), 8);
02323 
02324     vis_plugin_prefs = gtk_button_new_from_stock ("gtk-preferences");
02325     gtk_container_add (GTK_CONTAINER (hbuttonbox6), vis_plugin_prefs);
02326     gtk_widget_set_sensitive (vis_plugin_prefs, FALSE);
02327     gtk_widget_set_can_default(vis_plugin_prefs, TRUE);
02328 
02329     vis_plugin_info = gtk_button_new_from_stock ("gtk-dialog-info");
02330     gtk_container_add (GTK_CONTAINER (hbuttonbox6), vis_plugin_info);
02331     gtk_widget_set_sensitive (vis_plugin_info, FALSE);
02332     gtk_widget_set_can_default(vis_plugin_info, TRUE);
02333 
02334     vis_label = gtk_label_new (_("<b>Visualization</b>"));
02335     gtk_notebook_set_tab_label (GTK_NOTEBOOK (plugin_notebook), gtk_notebook_get_nth_page (GTK_NOTEBOOK (plugin_notebook), 2), vis_label);
02336     gtk_label_set_use_markup (GTK_LABEL (vis_label), TRUE);
02337 
02338     vbox25 = gtk_vbox_new (FALSE, 0);
02339     gtk_container_add (GTK_CONTAINER (plugin_notebook), vbox25);
02340     gtk_container_set_border_width (GTK_CONTAINER (vbox25), 12);
02341 
02342     alignment58 = gtk_alignment_new (0.5, 0.5, 1, 1);
02343     gtk_box_pack_start (GTK_BOX (vbox25), alignment58, FALSE, FALSE, 4);
02344     gtk_alignment_set_padding (GTK_ALIGNMENT (alignment58), 0, 6, 0, 0);
02345 
02346     label64 = gtk_label_new (_("Effect plugins:"));
02347     gtk_container_add (GTK_CONTAINER (alignment58), label64);
02348     gtk_misc_set_alignment (GTK_MISC (label64), 0, 0.5);
02349 
02350     scrolledwindow9 = gtk_scrolled_window_new (NULL, NULL);
02351     gtk_box_pack_start (GTK_BOX (vbox25), scrolledwindow9, TRUE, TRUE, 0);
02352     gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow9), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
02353     gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow9), GTK_SHADOW_IN);
02354 
02355     effect_plugin_view = gtk_tree_view_new ();
02356     gtk_container_add (GTK_CONTAINER (scrolledwindow9), effect_plugin_view);
02357     gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (effect_plugin_view), TRUE);
02358     gtk_tree_view_set_reorderable (GTK_TREE_VIEW (effect_plugin_view), TRUE);
02359 
02360     hbuttonbox9 = gtk_hbutton_box_new ();
02361     gtk_box_pack_start (GTK_BOX (vbox25), hbuttonbox9, FALSE, FALSE, 8);
02362     gtk_button_box_set_layout (GTK_BUTTON_BOX (hbuttonbox9), GTK_BUTTONBOX_START);
02363     gtk_box_set_spacing (GTK_BOX (hbuttonbox9), 8);
02364 
02365     effect_plugin_prefs = gtk_button_new_from_stock ("gtk-preferences");
02366     gtk_container_add (GTK_CONTAINER (hbuttonbox9), effect_plugin_prefs);
02367     gtk_widget_set_sensitive (effect_plugin_prefs, FALSE);
02368     gtk_widget_set_can_default(effect_plugin_prefs, TRUE);
02369 
02370     effect_plugin_info = gtk_button_new_from_stock ("gtk-dialog-info");
02371     gtk_container_add (GTK_CONTAINER (hbuttonbox9), effect_plugin_info);
02372     gtk_widget_set_sensitive (effect_plugin_info, FALSE);
02373     gtk_widget_set_can_default(effect_plugin_info, TRUE);
02374 
02375     effects_label = gtk_label_new (_("<b>Effects</b>"));
02376     gtk_notebook_set_tab_label (GTK_NOTEBOOK (plugin_notebook), gtk_notebook_get_nth_page (GTK_NOTEBOOK (plugin_notebook), 3), effects_label);
02377     gtk_label_set_use_markup (GTK_LABEL (effects_label), TRUE);
02378 
02379 
02380 
02381     gtk_label_set_mnemonic_widget (GTK_LABEL (input_plugin_list_label), category_notebook);
02382     gtk_label_set_mnemonic_widget (GTK_LABEL (label11), category_notebook);
02383     gtk_label_set_mnemonic_widget (GTK_LABEL (label53), category_notebook);
02384     gtk_label_set_mnemonic_widget (GTK_LABEL (label64), category_notebook);
02385 
02386 
02387 
02388     g_signal_connect_after(G_OBJECT(input_plugin_view), "realize",
02389                            G_CALLBACK(on_input_plugin_view_realize),
02390                            NULL);
02391     g_signal_connect_after(G_OBJECT(general_plugin_view), "realize",
02392                            G_CALLBACK(on_general_plugin_view_realize),
02393                            NULL);
02394     g_signal_connect_after(G_OBJECT(vis_plugin_view), "realize",
02395                            G_CALLBACK(on_vis_plugin_view_realize),
02396                            NULL);
02397     g_signal_connect_after(G_OBJECT(effect_plugin_view), "realize",
02398                            G_CALLBACK(on_effect_plugin_view_realize),
02399                            NULL);
02400 
02401 
02402 
02403     /* plugin->input page */
02404     g_object_set_data(G_OBJECT(input_plugin_view), "plugin_type" , GINT_TO_POINTER(PLUGIN_VIEW_TYPE_INPUT));
02405     g_signal_connect(G_OBJECT(input_plugin_view), "row-activated",
02406                      G_CALLBACK(plugin_treeview_open_prefs),
02407                      NULL);
02408     g_signal_connect(G_OBJECT(input_plugin_view), "cursor-changed",
02409                      G_CALLBACK(plugin_treeview_enable_prefs),
02410                      input_plugin_prefs);
02411 
02412     g_signal_connect_swapped(G_OBJECT(input_plugin_prefs), "clicked",
02413                              G_CALLBACK(plugin_treeview_open_prefs),
02414                              input_plugin_view);
02415 
02416     g_signal_connect(G_OBJECT(input_plugin_view), "cursor-changed",
02417                      G_CALLBACK(plugin_treeview_enable_info),
02418                      input_plugin_info);
02419     g_signal_connect_swapped(G_OBJECT(input_plugin_info), "clicked",
02420                              G_CALLBACK(plugin_treeview_open_info),
02421                              input_plugin_view);
02422 
02423 
02424     /* plugin->general page */
02425 
02426     g_object_set_data(G_OBJECT(general_plugin_view), "plugin_type" , GINT_TO_POINTER(PLUGIN_VIEW_TYPE_GENERAL));
02427     g_signal_connect(G_OBJECT(general_plugin_view), "row-activated",
02428                      G_CALLBACK(plugin_treeview_open_prefs),
02429                      NULL);
02430 
02431     g_signal_connect(G_OBJECT(general_plugin_view), "cursor-changed",
02432                      G_CALLBACK(plugin_treeview_enable_prefs),
02433                      general_plugin_prefs);
02434 
02435     g_signal_connect_swapped(G_OBJECT(general_plugin_prefs), "clicked",
02436                              G_CALLBACK(plugin_treeview_open_prefs),
02437                              general_plugin_view);
02438 
02439     g_signal_connect(G_OBJECT(general_plugin_view), "cursor-changed",
02440                      G_CALLBACK(plugin_treeview_enable_info),
02441                      general_plugin_info);
02442     g_signal_connect_swapped(G_OBJECT(general_plugin_info), "clicked",
02443                              G_CALLBACK(plugin_treeview_open_info),
02444                              general_plugin_view);
02445 
02446 
02447     /* plugin->vis page */
02448 
02449     g_object_set_data(G_OBJECT(vis_plugin_view), "plugin_type" , GINT_TO_POINTER(PLUGIN_VIEW_TYPE_VIS));
02450     g_signal_connect(G_OBJECT(vis_plugin_view), "row-activated",
02451                      G_CALLBACK(plugin_treeview_open_prefs),
02452                      NULL);
02453     g_signal_connect_swapped(G_OBJECT(vis_plugin_prefs), "clicked",
02454                              G_CALLBACK(plugin_treeview_open_prefs),
02455                              vis_plugin_view);
02456     g_signal_connect(G_OBJECT(vis_plugin_view), "cursor-changed",
02457                      G_CALLBACK(plugin_treeview_enable_prefs), vis_plugin_prefs);
02458 
02459     g_signal_connect(G_OBJECT(vis_plugin_view), "cursor-changed",
02460                      G_CALLBACK(plugin_treeview_enable_info), vis_plugin_info);
02461     g_signal_connect_swapped(G_OBJECT(vis_plugin_info), "clicked",
02462                              G_CALLBACK(plugin_treeview_open_info),
02463                              vis_plugin_view);
02464 
02465 
02466     /* plugin->effects page */
02467 
02468     g_object_set_data(G_OBJECT(effect_plugin_view), "plugin_type" , GINT_TO_POINTER(PLUGIN_VIEW_TYPE_EFFECT));
02469     g_signal_connect(G_OBJECT(effect_plugin_view), "row-activated",
02470                      G_CALLBACK(plugin_treeview_open_prefs),
02471                      NULL);
02472     g_signal_connect_swapped(G_OBJECT(effect_plugin_prefs), "clicked",
02473                              G_CALLBACK(plugin_treeview_open_prefs),
02474                              effect_plugin_view);
02475     g_signal_connect(G_OBJECT(effect_plugin_view), "cursor-changed",
02476                      G_CALLBACK(plugin_treeview_enable_prefs), effect_plugin_prefs);
02477 
02478     g_signal_connect(G_OBJECT(effect_plugin_view), "cursor-changed",
02479                      G_CALLBACK(plugin_treeview_enable_info), effect_plugin_info);
02480     g_signal_connect_swapped(G_OBJECT(effect_plugin_info), "clicked",
02481                              G_CALLBACK(plugin_treeview_open_info),
02482                              effect_plugin_view);
02483 
02484 }
02485 
02486 static void
02487 destroy_plugin_page(GList *list)
02488 {
02489     GList *iter;
02490 
02491     MOWGLI_ITER_FOREACH(iter, list)
02492     {
02493         Plugin *plugin = PLUGIN(iter->data);
02494         if (plugin->settings && plugin->settings->data) {
02495             plugin->settings->data = NULL;
02496             if (plugin->settings->apply)
02497                 plugin->settings->apply();
02498             if (plugin->settings->cleanup)
02499                 plugin->settings->cleanup();
02500         }
02501     }
02502 }
02503 
02504 static void
02505 destroy_plugin_pages(void)
02506 {
02507     destroy_plugin_page(plugin_get_list(PLUGIN_TYPE_INPUT));
02508     destroy_plugin_page(plugin_get_list(PLUGIN_TYPE_GENERAL));
02509     destroy_plugin_page(plugin_get_list(PLUGIN_TYPE_VIS));
02510     destroy_plugin_page(plugin_get_list(PLUGIN_TYPE_EFFECT));
02511 }
02512 
02513 static gboolean
02514 prefswin_destroy(GtkWidget *window, GdkEvent *event, gpointer data)
02515 {
02516     destroy_plugin_pages();
02517     prefswin = NULL;
02518     category_notebook = NULL;
02519     gtk_widget_destroy(filepopup_settings);
02520     filepopup_settings = NULL;
02521     gtk_widget_destroy(window);
02522     return TRUE;
02523 }
02524 
02525 static void
02526 create_plugin_page(GList *list)
02527 {
02528     GList *iter;
02529 
02530     MOWGLI_ITER_FOREACH(iter, list)
02531     {
02532         Plugin *plugin = PLUGIN(iter->data);
02533         if (plugin->settings && plugin->settings->type == PREFERENCES_PAGE) {
02534             create_plugin_preferences_page(plugin->settings);
02535         }
02536     }
02537 }
02538 
02539 static void
02540 create_plugin_pages(void)
02541 {
02542     create_plugin_page(plugin_get_list(PLUGIN_TYPE_INPUT));
02543     create_plugin_page(plugin_get_list(PLUGIN_TYPE_GENERAL));
02544     create_plugin_page(plugin_get_list(PLUGIN_TYPE_VIS));
02545     create_plugin_page(plugin_get_list(PLUGIN_TYPE_EFFECT));
02546 }
02547 
02548 /* GtkWidget * * create_prefs_window (void) */
02549 void * * create_prefs_window (void)
02550 {
02551     gchar *aud_version_string;
02552 
02553     GtkWidget *vbox;
02554     GtkWidget *hbox1;
02555     GtkWidget *scrolledwindow6;
02556     GtkWidget *hseparator1;
02557     GtkWidget *hbox4;
02558     GtkWidget *audversionlabel;
02559     GtkWidget *prefswin_button_box;
02560     GtkWidget *hbox11;
02561     GtkWidget *image10;
02562     GtkWidget *close;
02563     GtkAccelGroup *accel_group;
02564 
02565     accel_group = gtk_accel_group_new ();
02566 
02567     prefswin = gtk_window_new (GTK_WINDOW_TOPLEVEL);
02568     gtk_window_set_type_hint (GTK_WINDOW (prefswin), GDK_WINDOW_TYPE_HINT_DIALOG);
02569     gtk_container_set_border_width (GTK_CONTAINER (prefswin), 12);
02570     gtk_window_set_title (GTK_WINDOW (prefswin), _("Audacious Preferences"));
02571     gtk_window_set_position (GTK_WINDOW (prefswin), GTK_WIN_POS_CENTER);
02572     gtk_window_set_default_size (GTK_WINDOW (prefswin), 680, 400);
02573 
02574     vbox = gtk_vbox_new (FALSE, 0);
02575     gtk_container_add (GTK_CONTAINER (prefswin), vbox);
02576 
02577     hbox1 = gtk_hbox_new (FALSE, 8);
02578     gtk_box_pack_start (GTK_BOX (vbox), hbox1, TRUE, TRUE, 0);
02579 
02580     scrolledwindow6 = gtk_scrolled_window_new (NULL, NULL);
02581     gtk_box_pack_start (GTK_BOX (hbox1), scrolledwindow6, TRUE, TRUE, 0);
02582     gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow6), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
02583     gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow6), GTK_SHADOW_IN);
02584 
02585     category_treeview = gtk_tree_view_new ();
02586     gtk_container_add (GTK_CONTAINER (scrolledwindow6), category_treeview);
02587     gtk_widget_set_size_request (category_treeview, 172, -1);
02588     gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (category_treeview), FALSE);
02589 
02590     category_notebook = gtk_notebook_new ();
02591     gtk_box_pack_start (GTK_BOX (hbox1), category_notebook, TRUE, TRUE, 0);
02592 
02593     gtk_widget_set_can_focus (category_notebook, FALSE);
02594     gtk_notebook_set_show_tabs (GTK_NOTEBOOK (category_notebook), FALSE);
02595     gtk_notebook_set_show_border (GTK_NOTEBOOK (category_notebook), FALSE);
02596     gtk_notebook_set_scrollable (GTK_NOTEBOOK (category_notebook), TRUE);
02597 
02598 
02599 
02600     create_audio_category();
02601     create_replay_gain_category();
02602     create_connectivity_category();
02603     create_playback_category();
02604     create_playlist_category();
02605     create_plugin_category();
02606     create_plugin_pages();
02607 
02608     hseparator1 = gtk_hseparator_new ();
02609     gtk_box_pack_start (GTK_BOX (vbox), hseparator1, FALSE, FALSE, 6);
02610 
02611     hbox4 = gtk_hbox_new (FALSE, 0);
02612     gtk_box_pack_start (GTK_BOX (vbox), hbox4, FALSE, FALSE, 0);
02613 
02614     audversionlabel = gtk_label_new ("");
02615     gtk_box_pack_start (GTK_BOX (hbox4), audversionlabel, FALSE, FALSE, 0);
02616     gtk_label_set_use_markup (GTK_LABEL (audversionlabel), TRUE);
02617 
02618     prefswin_button_box = gtk_hbutton_box_new ();
02619     gtk_box_pack_start (GTK_BOX (hbox4), prefswin_button_box, TRUE, TRUE, 0);
02620     gtk_button_box_set_layout (GTK_BUTTON_BOX (prefswin_button_box), GTK_BUTTONBOX_END);
02621     gtk_box_set_spacing (GTK_BOX (prefswin_button_box), 6);
02622 
02623     hbox11 = gtk_hbox_new (FALSE, 2);
02624 
02625     image10 = gtk_image_new_from_stock ("gtk-refresh", GTK_ICON_SIZE_BUTTON);
02626     gtk_box_pack_start (GTK_BOX (hbox11), image10, FALSE, FALSE, 0);
02627 
02628     close = gtk_button_new_from_stock ("gtk-close");
02629     gtk_container_add (GTK_CONTAINER (prefswin_button_box), close);
02630     gtk_widget_set_can_default(close, TRUE);
02631     gtk_widget_add_accelerator (close, "clicked", accel_group,
02632                                 GDK_Escape, (GdkModifierType) 0,
02633                                 GTK_ACCEL_VISIBLE);
02634 
02635 
02636     gtk_window_add_accel_group (GTK_WINDOW (prefswin), accel_group);
02637 
02638     /* connect signals */
02639     g_signal_connect(G_OBJECT(prefswin), "delete_event",
02640                      G_CALLBACK(prefswin_destroy),
02641                      NULL);
02642     g_signal_connect_swapped(G_OBJECT(close), "clicked",
02643                              G_CALLBACK(prefswin_destroy),
02644                              GTK_OBJECT (prefswin));
02645 
02646     /* create category view */
02647     on_category_treeview_realize ((GtkTreeView *) category_treeview,
02648      (GtkNotebook *) category_notebook);
02649 
02650     /* audacious version label */
02651 
02652     aud_version_string = g_strdup_printf
02653      ("<span size='small'>%s (%s)</span>", "Audacious " PACKAGE_VERSION,
02654      BUILDSTAMP);
02655 
02656     gtk_label_set_markup( GTK_LABEL(audversionlabel) , aud_version_string );
02657     g_free(aud_version_string);
02658     gtk_widget_show_all(vbox);
02659 
02660     return & prefswin;
02661 }
02662 
02663 void
02664 destroy_prefs_window(void)
02665 {
02666     prefswin_destroy(prefswin, NULL, NULL);
02667 }
02668 
02669 void
02670 create_plugin_preferences_page(PluginPreferences *settings)
02671 {
02672     g_return_if_fail(settings->type == PREFERENCES_PAGE);
02673 
02674     if (settings->data != NULL)
02675         return;
02676 
02677     if (settings->init)
02678         settings->init();
02679 
02680     GtkWidget *vbox;
02681     vbox = gtk_vbox_new(FALSE, 5);
02682 
02683     create_widgets(GTK_BOX(vbox), settings->prefs, settings->n_prefs);
02684     gtk_widget_show_all(vbox);
02685     prefswin_page_new(vbox, settings->title, settings->imgurl);
02686 
02687     settings->data = (gpointer) vbox;
02688 }
02689 
02690 void
02691 destroy_plugin_preferences_page(PluginPreferences *settings)
02692 {
02693     if (settings->data) {
02694         if (settings->apply)
02695             settings->apply();
02696 
02697         prefswin_page_destroy(GTK_WIDGET(settings->data));
02698         settings->data = NULL;
02699 
02700         if (settings->cleanup)
02701             settings->cleanup();
02702     }
02703 }
02704 
02705 void
02706 show_prefs_window(void)
02707 {
02708     gtk_window_present(GTK_WINDOW(prefswin)); /* show or raise prefs window */
02709 }
02710 
02711 void
02712 hide_prefs_window(void)
02713 {
02714     g_return_if_fail(prefswin);
02715     gtk_widget_hide(GTK_WIDGET(prefswin));
02716 }
02717 
02718 static void prefswin_page_queue_new (GtkWidget * container, const gchar * name,
02719  const gchar * imgurl)
02720 {
02721     CategoryQueueEntry *ent = g_new0(CategoryQueueEntry, 1);
02722 
02723     ent->container = container;
02724     ent->pg_name = name;
02725     ent->img_url = imgurl;
02726 
02727     if (category_queue)
02728         ent->next = category_queue;
02729 
02730     category_queue = ent;
02731 }
02732 
02733 static void
02734 prefswin_page_queue_destroy(CategoryQueueEntry *ent)
02735 {
02736     category_queue = ent->next;
02737     g_free(ent);
02738 }
02739 
02740 /*
02741  * Public APIs for adding new pages to the prefs window.
02742  *
02743  * Basically, the concept here is that third party components can register themselves in the root
02744  * preferences window.
02745  *
02746  * From a usability standpoint this makes the application look more "united", instead of cluttered
02747  * and malorganised. Hopefully this option will be used further in the future.
02748  *
02749  *    - nenolod
02750  */
02751 /* gint prefswin_page_new (GtkWidget * container, const gchar * name,
02752  const gchar * imgurl) */
02753 gint prefswin_page_new (void * container, const gchar * name, const gchar *
02754  imgurl)
02755 {
02756     GtkTreeModel *model;
02757     GtkTreeIter iter;
02758     GdkPixbuf *img = NULL;
02759     GtkTreeView *treeview = GTK_TREE_VIEW(category_treeview);
02760     gint id;
02761 
02762     if (treeview == NULL || category_notebook == NULL)
02763     {
02764         prefswin_page_queue_new(container, name, imgurl);
02765         return -1;
02766     }
02767 
02768     model = gtk_tree_view_get_model(treeview);
02769 
02770     if (model == NULL)
02771     {
02772         prefswin_page_queue_new(container, name, imgurl);
02773         return -1;
02774     }
02775 
02776     /* Make sure the widgets are visible. */
02777     gtk_widget_show(container);
02778     id = gtk_notebook_append_page(GTK_NOTEBOOK(category_notebook), container, NULL);
02779 
02780     if (id == -1)
02781         return -1;
02782 
02783     if (imgurl != NULL)
02784         img = gdk_pixbuf_new_from_file(imgurl, NULL);
02785 
02786     gtk_list_store_append(GTK_LIST_STORE(model), &iter);
02787     gtk_list_store_set(GTK_LIST_STORE(model), &iter,
02788                        CATEGORY_VIEW_COL_ICON, img,
02789                        CATEGORY_VIEW_COL_NAME,
02790                        name, CATEGORY_VIEW_COL_ID, id, -1);
02791 
02792     if (img != NULL)
02793         g_object_unref(img);
02794 
02795     return id;
02796 }
02797 
02798 void
02799 prefswin_page_destroy(GtkWidget *container)
02800 {
02801     GtkTreeModel *model;
02802     GtkTreeIter iter;
02803     GtkTreeView *treeview = GTK_TREE_VIEW(category_treeview);
02804     gboolean ret;
02805     gint id;
02806     gint index = -1;
02807 
02808     if (category_notebook == NULL || treeview == NULL || container == NULL)
02809         return;
02810 
02811     id = gtk_notebook_page_num(GTK_NOTEBOOK(category_notebook), container);
02812 
02813     if (id == -1)
02814         return;
02815 
02816     gtk_notebook_remove_page(GTK_NOTEBOOK(category_notebook), id);
02817 
02818     model = gtk_tree_view_get_model(treeview);
02819 
02820     if (model == NULL)
02821         return;
02822 
02823     ret = gtk_tree_model_get_iter_first(model, &iter);
02824 
02825     while (ret == TRUE)
02826     {
02827         gtk_tree_model_get(model, &iter, CATEGORY_VIEW_COL_ID, &index, -1);
02828 
02829         if (index == id)
02830         {
02831             gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
02832             ret = gtk_tree_model_get_iter_first(model, &iter);
02833             continue;
02834         }
02835 
02836         if (index > id)
02837         {
02838             index--;
02839             gtk_list_store_set(GTK_LIST_STORE(model), &iter, CATEGORY_VIEW_COL_ID, index, -1);
02840         }
02841 
02842         ret = gtk_tree_model_iter_next(model, &iter);
02843     }
02844 }
02845 
02846 static void sw_volume_toggled (void)
02847 {
02848     gint vol[2];
02849 
02850     if (cfg.software_volume_control)
02851     {
02852         vol[0] = cfg.sw_volume_left;
02853         vol[1] = cfg.sw_volume_right;
02854     }
02855     else
02856         input_get_volume (& vol[0], & vol[1]);
02857 
02858     hook_call ("volume set", vol);
02859 }