Audacious $Id:Doxyfile42802007-03-2104:39:00Znenolod$
|
00001 /* Audacious - Cross-platform multimedia player 00002 * Copyright (C) 2005-2011 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 #include <string.h> 00021 #include <stdio.h> 00022 00023 #include <gdk/gdkkeysyms.h> 00024 #include <gtk/gtk.h> 00025 00026 #include <libaudcore/hook.h> 00027 00028 #include "audconfig.h" 00029 #include "config.h" 00030 #include "configdb.h" 00031 #include "debug.h" 00032 #include "gtk-compat.h" 00033 #include "i18n.h" 00034 #include "misc.h" 00035 #include "output.h" 00036 #include "playback.h" 00037 #include "playlist.h" 00038 #include "playlist-utils.h" 00039 #include "plugin.h" 00040 #include "plugins.h" 00041 #include "preferences.h" 00042 #include "ui_preferences.h" 00043 00044 #ifdef USE_CHARDET 00045 #include <libguess.h> 00046 #endif 00047 00048 #define TITLESTRING_UPDATE_TIMEOUT 3 00049 00050 static void sw_volume_toggled (void); 00051 00052 enum CategoryViewCols { 00053 CATEGORY_VIEW_COL_ICON, 00054 CATEGORY_VIEW_COL_NAME, 00055 CATEGORY_VIEW_COL_ID, 00056 CATEGORY_VIEW_N_COLS 00057 }; 00058 00059 typedef struct { 00060 const gchar *icon_path; 00061 const gchar *name; 00062 } Category; 00063 00064 typedef struct { 00065 const gchar *name; 00066 const gchar *tag; 00067 } TitleFieldTag; 00068 00069 static /* GtkWidget * */ void * prefswin = NULL; 00070 static GtkWidget *filepopup_settings = NULL; 00071 static GtkWidget *category_treeview = NULL; 00072 static GtkWidget *category_notebook = NULL; 00073 GtkWidget *filepopupbutton = NULL; 00074 00075 /* filepopup settings widgets */ 00076 GtkWidget *filepopup_settings_cover_name_include; 00077 GtkWidget *filepopup_settings_cover_name_exclude; 00078 GtkWidget *filepopup_settings_recurse_for_cover; 00079 GtkWidget *filepopup_settings_recurse_for_cover_depth; 00080 GtkWidget *filepopup_settings_recurse_for_cover_depth_box; 00081 GtkWidget *filepopup_settings_use_file_cover; 00082 GtkWidget *filepopup_settings_showprogressbar; 00083 GtkWidget *filepopup_settings_delay; 00084 00085 /* prefswin widgets */ 00086 GtkWidget *titlestring_entry; 00087 GtkWidget *filepopup_for_tuple_settings_button; 00088 static gint titlestring_timeout_counter = 0; 00089 00090 static Category categories[] = { 00091 {"audio.png", N_("Audio")}, 00092 {"connectivity.png", N_("Network")}, 00093 {"playlist.png", N_("Playlist")}, 00094 {"plugins.png", N_("Plugins")}, 00095 }; 00096 00097 static gint n_categories = G_N_ELEMENTS(categories); 00098 00099 static TitleFieldTag title_field_tags[] = { 00100 { N_("Artist") , "${artist}" }, 00101 { N_("Album") , "${album}" }, 00102 { N_("Title") , "${title}" }, 00103 { N_("Tracknumber"), "${track-number}" }, 00104 { N_("Genre") , "${genre}" }, 00105 { N_("Filename") , "${file-name}" }, 00106 { N_("Filepath") , "${file-path}" }, 00107 { N_("Date") , "${date}" }, 00108 { N_("Year") , "${year}" }, 00109 { N_("Comment") , "${comment}" }, 00110 { N_("Codec") , "${codec}" }, 00111 { N_("Quality") , "${quality}" }, 00112 }; 00113 static const guint n_title_field_tags = G_N_ELEMENTS(title_field_tags); 00114 00115 #ifdef USE_CHARDET 00116 static ComboBoxElements chardet_detector_presets[] = { 00117 {"", N_("None")}, 00118 {GUESS_REGION_AR, N_("Arabic")}, 00119 {GUESS_REGION_BL, N_("Baltic")}, 00120 {GUESS_REGION_CN, N_("Chinese")}, 00121 {GUESS_REGION_GR, N_("Greek")}, 00122 {GUESS_REGION_HW, N_("Hebrew")}, 00123 {GUESS_REGION_JP, N_("Japanese")}, 00124 {GUESS_REGION_KR, N_("Korean")}, 00125 {GUESS_REGION_PL, N_("Polish")}, 00126 {GUESS_REGION_RU, N_("Russian")}, 00127 {GUESS_REGION_TW, N_("Taiwanese")}, 00128 {GUESS_REGION_TR, N_("Turkish")}}; 00129 #endif 00130 00131 static ComboBoxElements bitdepth_elements[] = { 00132 { GINT_TO_POINTER(16), "16" }, 00133 { GINT_TO_POINTER(24), "24" }, 00134 { GINT_TO_POINTER(32), "32" }, 00135 {GINT_TO_POINTER (0), "Floating point"}, 00136 }; 00137 00138 typedef struct { 00139 void *next; 00140 GtkWidget *container; 00141 const gchar * pg_name; 00142 const gchar * img_url; 00143 } CategoryQueueEntry; 00144 00145 CategoryQueueEntry *category_queue = NULL; 00146 00147 static void * create_output_plugin_box (void); 00148 00149 static PreferencesWidget rg_mode_widgets[] = { 00150 {WIDGET_RADIO_BTN, N_("Single track mode"), .cfg_type = VALUE_BOOLEAN, .cfg = & cfg.replay_gain_track}, 00151 {WIDGET_RADIO_BTN, N_("Album mode"), .cfg_type = VALUE_BOOLEAN, .cfg = & cfg.replay_gain_album}}; 00152 00153 static PreferencesWidget audio_page_widgets[] = { 00154 {WIDGET_LABEL, N_("<b>Output Settings</b>")}, 00155 {WIDGET_CUSTOM, .data = {.populate = create_output_plugin_box}}, 00156 {WIDGET_COMBO_BOX, N_("Bit depth:"), 00157 .cfg_type = VALUE_INT, .cfg = & cfg.output_bit_depth, 00158 .data = {.combo = {bitdepth_elements, G_N_ELEMENTS (bitdepth_elements), TRUE}}}, 00159 {WIDGET_SPIN_BTN, N_("Buffer size:"), 00160 .cfg_type = VALUE_INT, .cfg = & cfg.output_buffer_size, 00161 .data = {.spin_btn = {100, 10000, 1000, N_("ms")}}}, 00162 {WIDGET_CHK_BTN, N_("Use software volume control (not recommended)"), 00163 .cfg_type = VALUE_BOOLEAN, .cfg = & cfg.software_volume_control, .callback = sw_volume_toggled}, 00164 {WIDGET_LABEL, N_("<b>Replay Gain</b>")}, 00165 {WIDGET_CHK_BTN, N_("Enable Replay Gain"), 00166 .cfg_type = VALUE_BOOLEAN, .cfg = & cfg.enable_replay_gain}, 00167 {WIDGET_BOX, .child = TRUE, .data = {.box = {rg_mode_widgets, G_N_ELEMENTS (rg_mode_widgets), TRUE}}}, 00168 {WIDGET_CHK_BTN, N_("Prevent clipping (recommended)"), .child = TRUE, 00169 .cfg_type = VALUE_BOOLEAN, .cfg = & cfg.enable_clipping_prevention}, 00170 {WIDGET_LABEL, N_("<b>Adjust Levels</b>"), .child = TRUE}, 00171 {WIDGET_SPIN_BTN, N_("Amplify all files:"), .child = TRUE, 00172 .cfg_type = VALUE_FLOAT, .cfg = & cfg.replay_gain_preamp, 00173 .data = {.spin_btn = {-15, 15, 0.1, N_("dB")}}}, 00174 {WIDGET_SPIN_BTN, N_("Amplify untagged files:"), .child = TRUE, 00175 .cfg_type = VALUE_FLOAT, .cfg = & cfg.default_gain, 00176 .data = {.spin_btn = {-15, 15, 0.1, N_("dB")}}}}; 00177 00178 static PreferencesWidget proxy_host_port_elements[] = { 00179 {WIDGET_ENTRY, N_("Proxy hostname:"), .cfg_type = VALUE_STRING, .cfg = & cfg.proxy_host}, 00180 {WIDGET_ENTRY, N_("Proxy port:"), .cfg_type = VALUE_STRING, .cfg = & cfg.proxy_port}}; 00181 00182 static PreferencesWidget proxy_auth_elements[] = { 00183 {WIDGET_ENTRY, N_("Proxy username:"), .cfg_type = VALUE_STRING, .cfg = & cfg.proxy_user}, 00184 {WIDGET_ENTRY, N_("Proxy password:"), .cfg_type = VALUE_STRING, .cfg = & cfg.proxy_user, 00185 .data = {.entry = {.password = TRUE}}}}; 00186 00187 static PreferencesWidget connectivity_page_widgets[] = { 00188 {WIDGET_LABEL, N_("<b>Proxy Configuration</b>"), NULL, NULL, NULL, FALSE}, 00189 {WIDGET_CHK_BTN, N_("Enable proxy usage"), .cfg_type = VALUE_BOOLEAN, .cfg = & cfg.use_proxy}, 00190 {WIDGET_TABLE, NULL, NULL, NULL, NULL, TRUE, {.table = {proxy_host_port_elements, G_N_ELEMENTS(proxy_host_port_elements)}}}, 00191 {WIDGET_CHK_BTN, N_("Use authentication with proxy"), .cfg_type = VALUE_BOOLEAN, .cfg = & cfg.use_proxy_auth}, 00192 {WIDGET_TABLE, NULL, NULL, NULL, NULL, TRUE, {.table = {proxy_auth_elements, G_N_ELEMENTS(proxy_auth_elements)}}}, 00193 {WIDGET_LABEL, N_("<span size=\"small\">Changing these settings will require a restart of Audacious.</span>"), NULL, NULL, NULL, FALSE, {.label = {"gtk-dialog-warning"}}}, 00194 }; 00195 00196 static PreferencesWidget chardet_elements[] = { 00197 #ifdef USE_CHARDET 00198 {WIDGET_COMBO_BOX, N_("Auto character encoding detector for:"), 00199 .cfg_type = VALUE_STRING, .cfg = & cfg.chardet_detector, .child = TRUE, 00200 .data = {.combo = {chardet_detector_presets, 00201 G_N_ELEMENTS (chardet_detector_presets), TRUE}}}, 00202 #endif 00203 {WIDGET_ENTRY, N_("Fallback character encodings:"), .cfg_type = VALUE_STRING, 00204 .cfg = & cfg.chardet_fallback, .callback = aud_config_chardet_update, 00205 .child = TRUE}}; 00206 00207 static PreferencesWidget playlist_page_widgets[] = { 00208 {WIDGET_LABEL, N_("<b>Behavior</b>"), NULL, NULL, NULL, FALSE}, 00209 {WIDGET_CHK_BTN, N_("Continue playback on startup"), 00210 .cfg_type = VALUE_BOOLEAN, .cfg = & cfg.resume_playback_on_startup}, 00211 {WIDGET_CHK_BTN, N_("Advance when the current song is deleted"), 00212 .cfg_type = VALUE_BOOLEAN, .cfg = & cfg.advance_on_delete}, 00213 {WIDGET_CHK_BTN, N_("Clear the playlist when opening files"), 00214 .cfg_type = VALUE_BOOLEAN, .cfg = & cfg.clear_playlist}, 00215 {WIDGET_CHK_BTN, N_("Open files in a temporary playlist"), 00216 .cfg_type = VALUE_BOOLEAN, .cfg = & cfg.open_to_temporary}, 00217 {WIDGET_LABEL, N_("<b>Metadata</b>"), NULL, NULL, NULL, FALSE}, 00218 {WIDGET_TABLE, NULL, NULL, NULL, NULL, TRUE, {.table = {chardet_elements, G_N_ELEMENTS(chardet_elements)}}}, 00219 }; 00220 00221 static void prefswin_page_queue_destroy(CategoryQueueEntry *ent); 00222 00223 static void 00224 change_category(GtkNotebook * notebook, 00225 GtkTreeSelection * selection) 00226 { 00227 GtkTreeModel *model; 00228 GtkTreeIter iter; 00229 gint index; 00230 00231 if (!gtk_tree_selection_get_selected(selection, &model, &iter)) 00232 return; 00233 00234 gtk_tree_model_get(model, &iter, CATEGORY_VIEW_COL_ID, &index, -1); 00235 gtk_notebook_set_current_page(notebook, index); 00236 } 00237 00238 static void 00239 editable_insert_text(GtkEditable * editable, 00240 const gchar * text, 00241 gint * pos) 00242 { 00243 gtk_editable_insert_text(editable, text, strlen(text), pos); 00244 } 00245 00246 static void 00247 titlestring_tag_menu_callback(GtkMenuItem * menuitem, 00248 gpointer data) 00249 { 00250 const gchar *separator = " - "; 00251 gint item = GPOINTER_TO_INT(data); 00252 gint pos; 00253 00254 pos = gtk_editable_get_position(GTK_EDITABLE(titlestring_entry)); 00255 00256 /* insert separator as needed */ 00257 if (g_utf8_strlen(gtk_entry_get_text(GTK_ENTRY(titlestring_entry)), -1) > 0) 00258 editable_insert_text(GTK_EDITABLE(titlestring_entry), separator, &pos); 00259 00260 editable_insert_text(GTK_EDITABLE(titlestring_entry), _(title_field_tags[item].tag), 00261 &pos); 00262 00263 gtk_editable_set_position(GTK_EDITABLE(titlestring_entry), pos); 00264 } 00265 00266 static void 00267 on_titlestring_help_button_clicked(GtkButton * button, 00268 gpointer data) 00269 { 00270 GtkMenu * menu = data; 00271 gtk_menu_popup (menu, NULL, NULL, NULL, NULL, 0, GDK_CURRENT_TIME); 00272 } 00273 00274 static gboolean 00275 titlestring_timeout_proc (gpointer data) 00276 { 00277 titlestring_timeout_counter--; 00278 00279 if(titlestring_timeout_counter <= 0) { 00280 titlestring_timeout_counter = 0; 00281 playlist_reformat_titles (); 00282 return FALSE; 00283 } else { 00284 return TRUE; 00285 } 00286 } 00287 00288 static void 00289 on_titlestring_entry_changed(GtkWidget * entry, 00290 gpointer data) 00291 { 00292 g_free(cfg.gentitle_format); 00293 cfg.gentitle_format = g_strdup(gtk_entry_get_text(GTK_ENTRY(entry))); 00294 00295 if(titlestring_timeout_counter == 0) { 00296 g_timeout_add_seconds (1, (GSourceFunc) titlestring_timeout_proc, NULL); 00297 } 00298 00299 titlestring_timeout_counter = TITLESTRING_UPDATE_TIMEOUT; 00300 } 00301 00302 static void 00303 on_titlestring_cbox_changed(GtkWidget * cbox, 00304 gpointer data) 00305 { 00306 gint position = gtk_combo_box_get_active(GTK_COMBO_BOX(cbox)); 00307 00308 cfg.titlestring_preset = position; 00309 gtk_widget_set_sensitive(GTK_WIDGET(data), (position == 6)); 00310 00311 playlist_reformat_titles (); 00312 } 00313 00314 static void 00315 on_font_btn_font_set(GtkFontButton * button, gchar **config) 00316 { 00317 g_free(*config); 00318 *config = g_strdup(gtk_font_button_get_font_name(button)); 00319 AUDDBG("Returned font name: \"%s\"\n", *config); 00320 void (*callback) (void) = g_object_get_data(G_OBJECT(button), "callback"); 00321 if (callback != NULL) callback(); 00322 } 00323 00324 static void 00325 plugin_preferences_ok(GtkWidget *widget, PluginPreferences *settings) 00326 { 00327 if (settings->apply) 00328 settings->apply(); 00329 00330 gtk_widget_destroy(GTK_WIDGET(settings->data)); 00331 } 00332 00333 static void 00334 plugin_preferences_apply(GtkWidget *widget, PluginPreferences *settings) 00335 { 00336 if (settings->apply) 00337 settings->apply(); 00338 } 00339 00340 static void 00341 plugin_preferences_cancel(GtkWidget *widget, PluginPreferences *settings) 00342 { 00343 if (settings->cancel) 00344 settings->cancel(); 00345 00346 gtk_widget_destroy(GTK_WIDGET(settings->data)); 00347 } 00348 00349 static void plugin_preferences_destroy(GtkWidget *widget, PluginPreferences *settings) 00350 { 00351 gtk_widget_destroy(widget); 00352 00353 if (settings->cleanup) 00354 settings->cleanup(); 00355 00356 settings->data = NULL; 00357 } 00358 00359 void plugin_preferences_show (PluginPreferences * settings) 00360 { 00361 GtkWidget *window; 00362 GtkWidget *vbox, *bbox, *ok, *apply, *cancel; 00363 00364 if (settings->data != NULL) { 00365 gtk_widget_show(GTK_WIDGET(settings->data)); 00366 return; 00367 } 00368 00369 if (settings->init) 00370 settings->init(); 00371 00372 const gchar * d = settings->domain; 00373 if (! d) 00374 { 00375 printf ("WARNING: PluginPreferences window with title \"%s\" did not " 00376 "declare its gettext domain. Text may not be translated correctly.\n", 00377 settings->title); 00378 d = "audacious-plugins"; 00379 } 00380 00381 window = gtk_window_new(GTK_WINDOW_TOPLEVEL); 00382 gtk_window_set_type_hint(GTK_WINDOW(window), GDK_WINDOW_TYPE_HINT_DIALOG); 00383 00384 if (settings->title) 00385 gtk_window_set_title ((GtkWindow *) window, dgettext (d, settings->title)); 00386 00387 gtk_container_set_border_width(GTK_CONTAINER(window), 10); 00388 g_signal_connect(G_OBJECT(window), "destroy", 00389 G_CALLBACK(plugin_preferences_destroy), settings); 00390 00391 vbox = gtk_vbox_new(FALSE, 10); 00392 create_widgets_with_domain ((GtkBox *) vbox, settings->prefs, 00393 settings->n_prefs, d); 00394 gtk_container_add(GTK_CONTAINER(window), vbox); 00395 00396 bbox = gtk_hbutton_box_new(); 00397 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END); 00398 gtk_box_set_spacing(GTK_BOX(bbox), 5); 00399 gtk_box_pack_start(GTK_BOX(vbox), bbox, FALSE, FALSE, 0); 00400 00401 ok = gtk_button_new_from_stock(GTK_STOCK_OK); 00402 g_signal_connect(G_OBJECT(ok), "clicked", 00403 G_CALLBACK(plugin_preferences_ok), settings); 00404 gtk_box_pack_start(GTK_BOX(bbox), ok, TRUE, TRUE, 0); 00405 gtk_widget_set_can_default (ok, TRUE); 00406 gtk_widget_grab_default(ok); 00407 00408 apply = gtk_button_new_from_stock(GTK_STOCK_APPLY); 00409 g_signal_connect(G_OBJECT(apply), "clicked", 00410 G_CALLBACK(plugin_preferences_apply), settings); 00411 gtk_box_pack_start(GTK_BOX(bbox), apply, TRUE, TRUE, 0); 00412 00413 cancel = gtk_button_new_from_stock(GTK_STOCK_CANCEL); 00414 g_signal_connect(G_OBJECT(cancel), "clicked", 00415 G_CALLBACK(plugin_preferences_cancel), settings); 00416 gtk_box_pack_start(GTK_BOX(bbox), cancel, TRUE, TRUE, 0); 00417 00418 gtk_window_set_transient_for(GTK_WINDOW(window), GTK_WINDOW(prefswin)); 00419 gtk_widget_show_all(window); 00420 settings->data = (gpointer)window; 00421 } 00422 00423 void plugin_preferences_cleanup (PluginPreferences * p) 00424 { 00425 if (p->data != NULL) 00426 { 00427 gtk_widget_destroy (p->data); 00428 p->data = NULL; 00429 } 00430 } 00431 00432 static void 00433 on_spin_btn_changed_gint(GtkSpinButton *button, gint *cfg) 00434 { 00435 *cfg = gtk_spin_button_get_value_as_int(button); 00436 } 00437 00438 static void 00439 on_spin_btn_changed_gfloat(GtkSpinButton *button, gfloat *cfg) 00440 { 00441 *cfg = (gfloat) gtk_spin_button_get_value(button); 00442 } 00443 00444 00445 static void fill_category_list (GtkTreeView * treeview, GtkNotebook * notebook) 00446 { 00447 GtkListStore *store; 00448 GtkCellRenderer *renderer; 00449 GtkTreeViewColumn *column; 00450 GtkTreeSelection *selection; 00451 GtkTreeIter iter; 00452 GdkPixbuf *img; 00453 CategoryQueueEntry *qlist; 00454 gint i; 00455 00456 column = gtk_tree_view_column_new(); 00457 gtk_tree_view_column_set_title(column, _("Category")); 00458 gtk_tree_view_append_column(treeview, column); 00459 gtk_tree_view_column_set_spacing(column, 2); 00460 00461 renderer = gtk_cell_renderer_pixbuf_new(); 00462 gtk_tree_view_column_pack_start(column, renderer, FALSE); 00463 gtk_tree_view_column_set_attributes(column, renderer, "pixbuf", 0, NULL); 00464 00465 renderer = gtk_cell_renderer_text_new(); 00466 gtk_tree_view_column_pack_start(column, renderer, FALSE); 00467 gtk_tree_view_column_set_attributes(column, renderer, "text", 1, NULL); 00468 00469 g_object_set ((GObject *) renderer, "wrap-width", 96, "wrap-mode", 00470 PANGO_WRAP_WORD_CHAR, NULL); 00471 00472 store = gtk_list_store_new(CATEGORY_VIEW_N_COLS, 00473 GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_INT); 00474 gtk_tree_view_set_model(treeview, GTK_TREE_MODEL(store)); 00475 00476 for (i = 0; i < n_categories; i ++) 00477 { 00478 gchar * path = g_strdup_printf ("%s/images/%s", 00479 get_path (AUD_PATH_DATA_DIR), categories[i].icon_path); 00480 img = gdk_pixbuf_new_from_file (path, NULL); 00481 g_free (path); 00482 00483 gtk_list_store_append(store, &iter); 00484 gtk_list_store_set(store, &iter, 00485 CATEGORY_VIEW_COL_ICON, img, 00486 CATEGORY_VIEW_COL_NAME, 00487 gettext(categories[i].name), CATEGORY_VIEW_COL_ID, 00488 i, -1); 00489 g_object_unref(img); 00490 } 00491 00492 selection = gtk_tree_view_get_selection(treeview); 00493 00494 g_signal_connect_swapped(selection, "changed", 00495 G_CALLBACK(change_category), notebook); 00496 00497 /* mark the treeview widget as available to third party plugins */ 00498 category_treeview = GTK_WIDGET(treeview); 00499 00500 /* prefswin_page_queue_destroy already pops the queue forward for us. */ 00501 for (qlist = category_queue; qlist != NULL; qlist = category_queue) 00502 { 00503 CategoryQueueEntry *ent = (CategoryQueueEntry *) qlist; 00504 00505 prefswin_page_new(ent->container, ent->pg_name, ent->img_url); 00506 prefswin_page_queue_destroy(ent); 00507 } 00508 } 00509 00510 static void 00511 on_show_filepopup_for_tuple_toggled(GtkToggleButton * button, gpointer data) 00512 { 00513 cfg.show_filepopup_for_tuple = gtk_toggle_button_get_active(button); 00514 00515 gtk_widget_set_sensitive(filepopup_for_tuple_settings_button, cfg.show_filepopup_for_tuple); 00516 } 00517 00518 static void 00519 on_recurse_for_cover_toggled(GtkToggleButton *button, gpointer data) 00520 { 00521 gtk_widget_set_sensitive(GTK_WIDGET(data), 00522 gtk_toggle_button_get_active(button)); 00523 } 00524 00525 static void 00526 on_filepopup_for_tuple_settings_clicked(GtkButton *button, gpointer data) 00527 { 00528 gtk_entry_set_text(GTK_ENTRY(filepopup_settings_cover_name_include), cfg.cover_name_include); 00529 gtk_entry_set_text(GTK_ENTRY(filepopup_settings_cover_name_exclude), cfg.cover_name_exclude); 00530 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(filepopup_settings_recurse_for_cover), cfg.recurse_for_cover); 00531 gtk_spin_button_set_value(GTK_SPIN_BUTTON(filepopup_settings_recurse_for_cover_depth), cfg.recurse_for_cover_depth); 00532 on_recurse_for_cover_toggled(GTK_TOGGLE_BUTTON(filepopup_settings_recurse_for_cover), filepopup_settings_recurse_for_cover_depth_box); 00533 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(filepopup_settings_use_file_cover), cfg.use_file_cover); 00534 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(filepopup_settings_showprogressbar), cfg.filepopup_showprogressbar); 00535 gtk_spin_button_set_value(GTK_SPIN_BUTTON(filepopup_settings_delay), cfg.filepopup_delay); 00536 00537 gtk_widget_show(filepopup_settings); 00538 } 00539 00540 static void 00541 on_filepopup_settings_ok_clicked(GtkButton *button, gpointer data) 00542 { 00543 g_free(cfg.cover_name_include); 00544 cfg.cover_name_include = g_strdup(gtk_entry_get_text(GTK_ENTRY(filepopup_settings_cover_name_include))); 00545 00546 g_free(cfg.cover_name_exclude); 00547 cfg.cover_name_exclude = g_strdup(gtk_entry_get_text(GTK_ENTRY(filepopup_settings_cover_name_exclude))); 00548 00549 cfg.recurse_for_cover = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(filepopup_settings_recurse_for_cover)); 00550 cfg.recurse_for_cover_depth = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(filepopup_settings_recurse_for_cover_depth)); 00551 cfg.use_file_cover = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(filepopup_settings_use_file_cover)); 00552 cfg.filepopup_showprogressbar = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(filepopup_settings_showprogressbar)); 00553 cfg.filepopup_delay = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(filepopup_settings_delay)); 00554 00555 gtk_widget_hide(filepopup_settings); 00556 } 00557 00558 static void 00559 on_filepopup_settings_cancel_clicked(GtkButton *button, gpointer data) 00560 { 00561 gtk_widget_hide(filepopup_settings); 00562 } 00563 00564 static void 00565 on_toggle_button_toggled(GtkToggleButton * button, gboolean *cfg) 00566 { 00567 *cfg = gtk_toggle_button_get_active(button); 00568 void (*callback) (void) = g_object_get_data(G_OBJECT(button), "callback"); 00569 if (callback != NULL) callback(); 00570 GtkWidget *child = g_object_get_data(G_OBJECT(button), "child"); 00571 if (child) gtk_widget_set_sensitive(GTK_WIDGET(child), *cfg); 00572 } 00573 00574 static void 00575 on_entry_changed(GtkEntry *entry, gchar **cfg) 00576 { 00577 void (*callback) (void) = g_object_get_data(G_OBJECT(entry), "callback"); 00578 const gchar *ret; 00579 00580 g_return_if_fail(cfg != NULL); 00581 00582 g_free(*cfg); 00583 00584 ret = gtk_entry_get_text(entry); 00585 00586 if (ret == NULL) 00587 *cfg = g_strdup(""); 00588 else 00589 *cfg = g_strdup(ret); 00590 00591 if (callback != NULL) callback(); 00592 } 00593 00594 static void 00595 on_cbox_changed_int(GtkComboBox * combobox, PreferencesWidget *widget) 00596 { 00597 gint position = 0; 00598 00599 position = gtk_combo_box_get_active(GTK_COMBO_BOX(combobox)); 00600 *((gint *)widget->cfg) = GPOINTER_TO_INT(widget->data.combo.elements[position].value); 00601 } 00602 00603 static void 00604 on_cbox_changed_string(GtkComboBox * combobox, PreferencesWidget *widget) 00605 { 00606 gint position = 0; 00607 00608 position = gtk_combo_box_get_active(GTK_COMBO_BOX(combobox)); 00609 00610 g_free(*((gchar **)widget->cfg)); 00611 00612 *((gchar **)widget->cfg) = g_strdup(widget->data.combo.elements[position].value); 00613 } 00614 00615 static void fill_cbox (GtkWidget * combobox, PreferencesWidget * widget) 00616 { 00617 guint i=0,index=0; 00618 00619 for (i = 0; i < widget->data.combo.n_elements; i ++) 00620 gtk_combo_box_text_append_text ((GtkComboBoxText *) combobox, 00621 _(widget->data.combo.elements[i].label)); 00622 00623 if (widget->data.combo.enabled) { 00624 switch (widget->cfg_type) { 00625 case VALUE_INT: 00626 g_signal_connect(combobox, "changed", 00627 G_CALLBACK(on_cbox_changed_int), widget); 00628 for(i=0; i<widget->data.combo.n_elements; i++) { 00629 if (GPOINTER_TO_INT(widget->data.combo.elements[i].value) == *((gint *) widget->cfg)) { 00630 index = i; 00631 break; 00632 } 00633 } 00634 break; 00635 case VALUE_STRING: 00636 g_signal_connect(combobox, "changed", 00637 G_CALLBACK(on_cbox_changed_string), widget); 00638 for(i=0; i<widget->data.combo.n_elements; i++) { 00639 if(!strcmp((gchar *)widget->data.combo.elements[i].value, *((gchar **)widget->cfg))) { 00640 index = i; 00641 break; 00642 } 00643 } 00644 break; 00645 case VALUE_NULL: 00646 break; 00647 default: 00648 g_warning("Unhandled cbox value type"); 00649 break; 00650 } 00651 gtk_combo_box_set_active(GTK_COMBO_BOX(combobox), index); 00652 } else { 00653 gtk_combo_box_set_active(GTK_COMBO_BOX(combobox), -1); 00654 gtk_widget_set_sensitive(GTK_WIDGET(combobox), 0); 00655 } 00656 } 00657 00658 void 00659 create_filepopup_settings(void) 00660 { 00661 GtkWidget *vbox; 00662 GtkWidget *table; 00663 00664 GtkWidget *label_cover_retrieve; 00665 GtkWidget *label_cover_search; 00666 GtkWidget *label_exclude; 00667 GtkWidget *label_include; 00668 GtkWidget *label_search_depth; 00669 GtkWidget *label_misc; 00670 GtkWidget *label_delay; 00671 00672 GtkAdjustment *recurse_for_cover_depth_adj; 00673 GtkAdjustment *delay_adj; 00674 GtkWidget *alignment; 00675 00676 GtkWidget *hbox; 00677 GtkWidget *hbuttonbox; 00678 GtkWidget *btn_cancel; 00679 GtkWidget *btn_ok; 00680 00681 filepopup_settings = gtk_window_new(GTK_WINDOW_TOPLEVEL); 00682 gtk_container_set_border_width(GTK_CONTAINER(filepopup_settings), 12); 00683 gtk_window_set_title(GTK_WINDOW(filepopup_settings), _("Popup Information Settings")); 00684 gtk_window_set_position(GTK_WINDOW(filepopup_settings), GTK_WIN_POS_CENTER_ON_PARENT); 00685 gtk_window_set_skip_taskbar_hint(GTK_WINDOW(filepopup_settings), TRUE); 00686 gtk_window_set_type_hint(GTK_WINDOW(filepopup_settings), GDK_WINDOW_TYPE_HINT_DIALOG); 00687 gtk_window_set_transient_for(GTK_WINDOW(filepopup_settings), GTK_WINDOW(prefswin)); 00688 00689 vbox = gtk_vbox_new(FALSE, 12); 00690 gtk_container_add(GTK_CONTAINER(filepopup_settings), vbox); 00691 00692 label_cover_retrieve = gtk_label_new(_("<b>Cover image retrieve</b>")); 00693 gtk_box_pack_start(GTK_BOX(vbox), label_cover_retrieve, FALSE, FALSE, 0); 00694 gtk_label_set_use_markup(GTK_LABEL(label_cover_retrieve), TRUE); 00695 gtk_misc_set_alignment(GTK_MISC(label_cover_retrieve), 0, 0.5); 00696 00697 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.")); 00698 gtk_box_pack_start(GTK_BOX(vbox), label_cover_search, FALSE, FALSE, 0); 00699 gtk_label_set_line_wrap(GTK_LABEL(label_cover_search), TRUE); 00700 gtk_misc_set_alignment(GTK_MISC(label_cover_search), 0, 0); 00701 gtk_misc_set_padding(GTK_MISC(label_cover_search), 12, 0); 00702 00703 table = gtk_table_new(2, 2, FALSE); 00704 gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 0); 00705 gtk_table_set_row_spacings(GTK_TABLE(table), 4); 00706 gtk_table_set_col_spacings(GTK_TABLE(table), 4); 00707 00708 filepopup_settings_cover_name_include = gtk_entry_new(); 00709 gtk_table_attach(GTK_TABLE(table), filepopup_settings_cover_name_include, 1, 2, 0, 1, 00710 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 00711 (GtkAttachOptions) (0), 0, 0); 00712 gtk_entry_set_activates_default(GTK_ENTRY(filepopup_settings_cover_name_include), TRUE); 00713 00714 label_exclude = gtk_label_new(_("Exclude:")); 00715 gtk_table_attach(GTK_TABLE(table), label_exclude, 0, 1, 1, 2, 00716 (GtkAttachOptions) (0), 00717 (GtkAttachOptions) (0), 0, 0); 00718 gtk_misc_set_alignment(GTK_MISC(label_exclude), 0, 0.5); 00719 gtk_misc_set_padding(GTK_MISC(label_exclude), 12, 0); 00720 00721 label_include = gtk_label_new(_("Include:")); 00722 gtk_table_attach(GTK_TABLE(table), label_include, 0, 1, 0, 1, 00723 (GtkAttachOptions) (0), 00724 (GtkAttachOptions) (0), 0, 0); 00725 gtk_misc_set_alignment(GTK_MISC(label_include), 0, 0.5); 00726 gtk_misc_set_padding(GTK_MISC(label_include), 12, 0); 00727 00728 filepopup_settings_cover_name_exclude = gtk_entry_new(); 00729 gtk_table_attach(GTK_TABLE(table), filepopup_settings_cover_name_exclude, 1, 2, 1, 2, 00730 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 00731 (GtkAttachOptions) (0), 0, 0); 00732 gtk_entry_set_activates_default(GTK_ENTRY(filepopup_settings_cover_name_exclude), TRUE); 00733 00734 alignment = gtk_alignment_new(0.5, 0.5, 1, 1); 00735 gtk_box_pack_start(GTK_BOX(vbox), alignment, TRUE, TRUE, 0); 00736 gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 0, 12, 0); 00737 00738 filepopup_settings_recurse_for_cover = gtk_check_button_new_with_mnemonic(_("Recursively search for cover")); 00739 gtk_container_add(GTK_CONTAINER(alignment), filepopup_settings_recurse_for_cover); 00740 00741 alignment = gtk_alignment_new(0.5, 0.5, 1, 1); 00742 gtk_box_pack_start(GTK_BOX(vbox), alignment, FALSE, FALSE, 0); 00743 gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 0, 45, 0); 00744 00745 filepopup_settings_recurse_for_cover_depth_box = gtk_hbox_new(FALSE, 0); 00746 gtk_container_add(GTK_CONTAINER(alignment), filepopup_settings_recurse_for_cover_depth_box); 00747 00748 label_search_depth = gtk_label_new(_("Search depth: ")); 00749 gtk_box_pack_start(GTK_BOX(filepopup_settings_recurse_for_cover_depth_box), label_search_depth, TRUE, TRUE, 0); 00750 gtk_misc_set_padding(GTK_MISC(label_search_depth), 4, 0); 00751 00752 recurse_for_cover_depth_adj = (GtkAdjustment *) gtk_adjustment_new (0, 0, 00753 100, 1, 10, 0); 00754 filepopup_settings_recurse_for_cover_depth = gtk_spin_button_new(GTK_ADJUSTMENT(recurse_for_cover_depth_adj), 1, 0); 00755 gtk_box_pack_start(GTK_BOX(filepopup_settings_recurse_for_cover_depth_box), filepopup_settings_recurse_for_cover_depth, TRUE, TRUE, 0); 00756 gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(filepopup_settings_recurse_for_cover_depth), TRUE); 00757 00758 alignment = gtk_alignment_new(0.5, 0.5, 1, 1); 00759 gtk_box_pack_start(GTK_BOX(vbox), alignment, TRUE, TRUE, 0); 00760 gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 0, 12, 0); 00761 00762 filepopup_settings_use_file_cover = gtk_check_button_new_with_mnemonic(_("Use per-file cover")); 00763 gtk_container_add(GTK_CONTAINER(alignment), filepopup_settings_use_file_cover); 00764 00765 label_misc = gtk_label_new(_("<b>Miscellaneous</b>")); 00766 gtk_box_pack_start(GTK_BOX(vbox), label_misc, FALSE, FALSE, 0); 00767 gtk_label_set_use_markup(GTK_LABEL(label_misc), TRUE); 00768 gtk_misc_set_alignment(GTK_MISC(label_misc), 0, 0.5); 00769 00770 alignment = gtk_alignment_new(0.5, 0.5, 1, 1); 00771 gtk_box_pack_start(GTK_BOX(vbox), alignment, FALSE, FALSE, 0); 00772 gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 0, 12, 0); 00773 00774 filepopup_settings_showprogressbar = gtk_check_button_new_with_mnemonic(_("Show Progress bar for the current track")); 00775 gtk_container_add(GTK_CONTAINER(alignment), filepopup_settings_showprogressbar); 00776 00777 alignment = gtk_alignment_new(0, 0.5, 1, 1); 00778 gtk_box_pack_start(GTK_BOX(vbox), alignment, TRUE, TRUE, 0); 00779 gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 0, 12, 0); 00780 00781 hbox = gtk_hbox_new(FALSE, 0); 00782 gtk_container_add(GTK_CONTAINER(alignment), hbox); 00783 00784 label_delay = gtk_label_new(_("Delay until filepopup comes up: ")); 00785 gtk_box_pack_start(GTK_BOX(hbox), label_delay, TRUE, TRUE, 0); 00786 gtk_misc_set_alignment(GTK_MISC(label_delay), 0, 0.5); 00787 gtk_misc_set_padding(GTK_MISC(label_delay), 12, 0); 00788 00789 delay_adj = (GtkAdjustment *) gtk_adjustment_new (0, 0, 100, 1, 10, 0); 00790 filepopup_settings_delay = gtk_spin_button_new(GTK_ADJUSTMENT(delay_adj), 1, 0); 00791 gtk_box_pack_start(GTK_BOX(hbox), filepopup_settings_delay, TRUE, TRUE, 0); 00792 gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(filepopup_settings_delay), TRUE); 00793 00794 hbuttonbox = gtk_hbutton_box_new(); 00795 gtk_box_pack_start(GTK_BOX(vbox), hbuttonbox, FALSE, FALSE, 0); 00796 gtk_button_box_set_layout(GTK_BUTTON_BOX(hbuttonbox), GTK_BUTTONBOX_END); 00797 gtk_box_set_spacing(GTK_BOX(hbuttonbox), 6); 00798 00799 btn_cancel = gtk_button_new_from_stock("gtk-cancel"); 00800 gtk_container_add(GTK_CONTAINER(hbuttonbox), btn_cancel); 00801 00802 btn_ok = gtk_button_new_from_stock("gtk-ok"); 00803 gtk_container_add(GTK_CONTAINER(hbuttonbox), btn_ok); 00804 gtk_widget_set_can_default(btn_ok, TRUE); 00805 00806 g_signal_connect(G_OBJECT(filepopup_settings), "delete_event", 00807 G_CALLBACK(gtk_widget_hide_on_delete), 00808 NULL); 00809 g_signal_connect(G_OBJECT(btn_cancel), "clicked", 00810 G_CALLBACK(on_filepopup_settings_cancel_clicked), 00811 NULL); 00812 g_signal_connect(G_OBJECT(btn_ok), "clicked", 00813 G_CALLBACK(on_filepopup_settings_ok_clicked), 00814 NULL); 00815 g_signal_connect(G_OBJECT(filepopup_settings_recurse_for_cover), "toggled", 00816 G_CALLBACK(on_recurse_for_cover_toggled), 00817 filepopup_settings_recurse_for_cover_depth_box); 00818 00819 gtk_widget_grab_default(btn_ok); 00820 gtk_widget_show_all(vbox); 00821 } 00822 00823 static void create_spin_button (PreferencesWidget * widget, GtkWidget * * 00824 label_pre, GtkWidget * * spin_btn, GtkWidget * * label_past, const gchar * 00825 domain) 00826 { 00827 g_return_if_fail(widget->type == WIDGET_SPIN_BTN); 00828 00829 * label_pre = gtk_label_new (dgettext (domain, widget->label)); 00830 00831 *spin_btn = gtk_spin_button_new_with_range(widget->data.spin_btn.min, 00832 widget->data.spin_btn.max, 00833 widget->data.spin_btn.step); 00834 00835 00836 if (widget->tooltip) 00837 gtk_widget_set_tooltip_text (* spin_btn, dgettext (domain, 00838 widget->tooltip)); 00839 00840 if (widget->data.spin_btn.right_label) { 00841 * label_past = gtk_label_new (dgettext (domain, 00842 widget->data.spin_btn.right_label)); 00843 } 00844 00845 switch (widget->cfg_type) { 00846 case VALUE_INT: 00847 gtk_spin_button_set_value ((GtkSpinButton *) * spin_btn, * (gint *) widget->cfg); 00848 g_signal_connect(G_OBJECT(*spin_btn), "value_changed", 00849 G_CALLBACK(on_spin_btn_changed_gint), 00850 widget->cfg); 00851 break; 00852 case VALUE_FLOAT: 00853 gtk_spin_button_set_value ((GtkSpinButton *) * spin_btn, * (gfloat *) widget->cfg); 00854 g_signal_connect(G_OBJECT(*spin_btn), "value_changed", 00855 G_CALLBACK(on_spin_btn_changed_gfloat), 00856 widget->cfg); 00857 break; 00858 case VALUE_NULL: 00859 break; 00860 default: 00861 g_warning("Unsupported value type for spin button"); 00862 } 00863 } 00864 00865 void create_font_btn (PreferencesWidget * widget, GtkWidget * * label, 00866 GtkWidget * * font_btn, const gchar * domain) 00867 { 00868 *font_btn = gtk_font_button_new(); 00869 gtk_font_button_set_use_font(GTK_FONT_BUTTON(*font_btn), TRUE); 00870 gtk_font_button_set_use_size(GTK_FONT_BUTTON(*font_btn), TRUE); 00871 if (widget->label) { 00872 * label = gtk_label_new_with_mnemonic (dgettext (domain, widget->label)); 00873 gtk_label_set_use_markup(GTK_LABEL(*label), TRUE); 00874 gtk_misc_set_alignment(GTK_MISC(*label), 1, 0.5); 00875 gtk_label_set_justify(GTK_LABEL(*label), GTK_JUSTIFY_RIGHT); 00876 gtk_label_set_mnemonic_widget(GTK_LABEL(*label), *font_btn); 00877 } 00878 00879 if (widget->data.font_btn.title) 00880 gtk_font_button_set_title (GTK_FONT_BUTTON (* font_btn), 00881 dgettext (domain, widget->data.font_btn.title)); 00882 00883 gtk_font_button_set_font_name ((GtkFontButton *) * font_btn, * (gchar * *) widget->cfg); 00884 00885 g_object_set_data ((GObject *) (* font_btn), "callback", (void *) 00886 widget->callback); 00887 00888 g_signal_connect(G_OBJECT(*font_btn), "font_set", 00889 G_CALLBACK(on_font_btn_font_set), 00890 (gchar**)widget->cfg); 00891 } 00892 00893 static void create_entry (PreferencesWidget * widget, GtkWidget * * label, 00894 GtkWidget * * entry, const gchar * domain) 00895 { 00896 *entry = gtk_entry_new(); 00897 gtk_entry_set_visibility(GTK_ENTRY(*entry), !widget->data.entry.password); 00898 00899 if (widget->label) 00900 * label = gtk_label_new (dgettext (domain, widget->label)); 00901 00902 if (widget->tooltip) 00903 gtk_widget_set_tooltip_text (* entry, dgettext (domain, widget->tooltip)); 00904 00905 g_object_set_data ((GObject *) (* entry), "callback", (void *) 00906 widget->callback); 00907 00908 if (widget->cfg) 00909 { 00910 if (widget->cfg_type == VALUE_STRING) 00911 { 00912 if (* (gchar * *) widget->cfg) 00913 gtk_entry_set_text ((GtkEntry *) * entry, * (gchar * *) widget->cfg); 00914 00915 g_signal_connect (* entry, "changed", (GCallback) on_entry_changed, widget->cfg); 00916 } 00917 else 00918 printf ("WARNING: Invalid PreferencesWidget config type.\n"); 00919 } 00920 } 00921 00922 static void create_label (PreferencesWidget * widget, GtkWidget * * label, 00923 GtkWidget * * icon, const gchar * domain) 00924 { 00925 if (widget->data.label.stock_id) 00926 *icon = gtk_image_new_from_stock(widget->data.label.stock_id, GTK_ICON_SIZE_BUTTON); 00927 00928 * label = gtk_label_new_with_mnemonic (dgettext (domain, widget->label)); 00929 gtk_label_set_use_markup(GTK_LABEL(*label), TRUE); 00930 00931 if (widget->data.label.single_line == FALSE) 00932 gtk_label_set_line_wrap(GTK_LABEL(*label), TRUE); 00933 00934 gtk_misc_set_alignment(GTK_MISC(*label), 0, 0.5); 00935 } 00936 00937 static void create_cbox (PreferencesWidget * widget, GtkWidget * * label, 00938 GtkWidget * * combobox, const gchar * domain) 00939 { 00940 * combobox = gtk_combo_box_text_new (); 00941 00942 if (widget->label) { 00943 * label = gtk_label_new (dgettext (domain, widget->label)); 00944 } 00945 00946 fill_cbox (* combobox, widget); 00947 } 00948 00949 static void fill_table (GtkWidget * table, PreferencesWidget * elements, gint 00950 amt, const gchar * domain) 00951 { 00952 gint x; 00953 GtkWidget *widget_left, *widget_middle, *widget_right; 00954 GtkAttachOptions middle_policy = (GtkAttachOptions) (0); 00955 00956 for (x = 0; x < amt; ++x) { 00957 widget_left = widget_middle = widget_right = NULL; 00958 switch (elements[x].type) { 00959 case WIDGET_SPIN_BTN: 00960 create_spin_button (& elements[x], & widget_left, 00961 & widget_middle, & widget_right, domain); 00962 middle_policy = (GtkAttachOptions) (GTK_FILL); 00963 break; 00964 case WIDGET_LABEL: 00965 create_label (& elements[x], & widget_middle, & widget_left, 00966 domain); 00967 middle_policy = (GtkAttachOptions) (GTK_FILL); 00968 break; 00969 case WIDGET_FONT_BTN: 00970 create_font_btn (& elements[x], & widget_left, & widget_middle, 00971 domain); 00972 middle_policy = (GtkAttachOptions) (GTK_EXPAND | GTK_FILL); 00973 break; 00974 case WIDGET_ENTRY: 00975 create_entry (& elements[x], & widget_left, & widget_middle, 00976 domain); 00977 middle_policy = (GtkAttachOptions) (GTK_EXPAND | GTK_FILL); 00978 break; 00979 case WIDGET_COMBO_BOX: 00980 create_cbox (& elements[x], & widget_left, & widget_middle, 00981 domain); 00982 middle_policy = (GtkAttachOptions) (GTK_EXPAND | GTK_FILL); 00983 break; 00984 default: 00985 g_warning("Unsupported widget type %d in table", elements[x].type); 00986 } 00987 00988 if (widget_left) 00989 gtk_table_attach(GTK_TABLE (table), widget_left, 0, 1, x, x+1, 00990 (GtkAttachOptions) (0), 00991 (GtkAttachOptions) (0), 0, 0); 00992 00993 if (widget_middle) 00994 gtk_table_attach(GTK_TABLE(table), widget_middle, 1, widget_right ? 2 : 3, x, x+1, 00995 middle_policy, 00996 (GtkAttachOptions) (0), 4, 0); 00997 00998 if (widget_right) 00999 gtk_table_attach(GTK_TABLE(table), widget_right, 2, 3, x, x+1, 01000 (GtkAttachOptions) (0), 01001 (GtkAttachOptions) (0), 0, 0); 01002 } 01003 } 01004 01005 /* void create_widgets_with_domain (GtkBox * box, PreferencesWidget * widgets, 01006 gint amt, const gchar * domain) */ 01007 void create_widgets_with_domain (void * box, PreferencesWidget * widgets, gint 01008 amt, const gchar * domain) 01009 { 01010 gint x; 01011 GtkWidget *alignment = NULL, *widget = NULL; 01012 GtkWidget *child_box = NULL; 01013 GSList *radio_btn_group = NULL; 01014 01015 for (x = 0; x < amt; ++x) { 01016 if (widget && widgets[x].child) 01017 { 01018 if (!child_box) { 01019 child_box = gtk_vbox_new(FALSE, 0); 01020 g_object_set_data(G_OBJECT(widget), "child", child_box); 01021 alignment = gtk_alignment_new (0.5, 0.5, 1, 1); 01022 gtk_box_pack_start(box, alignment, FALSE, FALSE, 0); 01023 gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 0, 0, 12, 0); 01024 gtk_container_add (GTK_CONTAINER (alignment), child_box); 01025 01026 if (GTK_IS_TOGGLE_BUTTON (widget)) 01027 gtk_widget_set_sensitive (child_box, gtk_toggle_button_get_active ((GtkToggleButton *) widget)); 01028 } 01029 } else 01030 child_box = NULL; 01031 01032 alignment = gtk_alignment_new (0.5, 0.5, 1, 1); 01033 gtk_alignment_set_padding ((GtkAlignment *) alignment, 6, 0, 12, 0); 01034 gtk_box_pack_start(child_box ? GTK_BOX(child_box) : box, alignment, FALSE, FALSE, 0); 01035 01036 if (radio_btn_group && widgets[x].type != WIDGET_RADIO_BTN) 01037 radio_btn_group = NULL; 01038 01039 switch(widgets[x].type) { 01040 case WIDGET_CHK_BTN: 01041 widget = gtk_check_button_new_with_mnemonic (dgettext (domain, 01042 widgets[x].label)); 01043 g_object_set_data ((GObject *) widget, "callback", 01044 (void *) widgets[x].callback); 01045 01046 if (widgets[x].cfg) 01047 { 01048 if (widgets[x].cfg_type == VALUE_BOOLEAN) 01049 { 01050 gtk_toggle_button_set_active ((GtkToggleButton *) widget, * (gboolean *) widgets[x].cfg); 01051 g_signal_connect (widget, "toggled", (GCallback) on_toggle_button_toggled, widgets[x].cfg); 01052 } 01053 else 01054 printf ("WARNING: Invalid PreferencesWidget config type.\n"); 01055 } 01056 01057 break; 01058 case WIDGET_LABEL: 01059 gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 12, 0, 0, 0); 01060 01061 GtkWidget *label = NULL, *icon = NULL; 01062 create_label (& widgets[x], & label, & icon, domain); 01063 01064 if (icon == NULL) 01065 widget = label; 01066 else { 01067 widget = gtk_hbox_new(FALSE, 6); 01068 gtk_box_pack_start(GTK_BOX(widget), icon, FALSE, FALSE, 0); 01069 gtk_box_pack_start(GTK_BOX(widget), label, FALSE, FALSE, 0); 01070 } 01071 break; 01072 case WIDGET_RADIO_BTN: 01073 widget = gtk_radio_button_new_with_mnemonic (radio_btn_group, 01074 dgettext (domain, widgets[x].label)); 01075 radio_btn_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (widget)); 01076 01077 if (widgets[x].cfg) 01078 { 01079 if (widgets[x].cfg_type == VALUE_BOOLEAN) 01080 { 01081 gtk_toggle_button_set_active ((GtkToggleButton *) widget, * (gboolean *) widgets[x].cfg); 01082 g_signal_connect (widget, "toggled", (GCallback) on_toggle_button_toggled, widgets[x].cfg); 01083 } 01084 else 01085 printf ("WARNING: Invalid PreferencesWidget config type.\n"); 01086 } 01087 01088 break; 01089 case WIDGET_SPIN_BTN: 01090 widget = gtk_hbox_new(FALSE, 6); 01091 01092 GtkWidget *label_pre = NULL, *spin_btn = NULL, *label_past = NULL; 01093 create_spin_button (& widgets[x], & label_pre, & spin_btn, 01094 & label_past, domain); 01095 01096 if (label_pre) 01097 gtk_box_pack_start(GTK_BOX(widget), label_pre, FALSE, FALSE, 0); 01098 if (spin_btn) 01099 gtk_box_pack_start(GTK_BOX(widget), spin_btn, FALSE, FALSE, 0); 01100 if (label_past) 01101 gtk_box_pack_start(GTK_BOX(widget), label_past, FALSE, FALSE, 0); 01102 01103 break; 01104 case WIDGET_CUSTOM: /* custom widget. --nenolod */ 01105 if (widgets[x].data.populate) 01106 widget = widgets[x].data.populate(); 01107 else 01108 widget = NULL; 01109 01110 break; 01111 case WIDGET_FONT_BTN: 01112 widget = gtk_hbox_new(FALSE, 6); 01113 01114 GtkWidget *font_btn = NULL; 01115 create_font_btn (& widgets[x], & label, & font_btn, domain); 01116 01117 if (label) 01118 gtk_box_pack_start(GTK_BOX(widget), label, FALSE, FALSE, 0); 01119 if (font_btn) 01120 gtk_box_pack_start(GTK_BOX(widget), font_btn, FALSE, FALSE, 0); 01121 break; 01122 case WIDGET_TABLE: 01123 widget = gtk_table_new(widgets[x].data.table.rows, 3, FALSE); 01124 fill_table (widget, widgets[x].data.table.elem, 01125 widgets[x].data.table.rows, domain); 01126 gtk_table_set_row_spacings(GTK_TABLE(widget), 6); 01127 break; 01128 case WIDGET_ENTRY: 01129 widget = gtk_hbox_new(FALSE, 6); 01130 01131 GtkWidget *entry = NULL; 01132 create_entry (& widgets[x], & label, & entry, domain); 01133 01134 if (label) 01135 gtk_box_pack_start(GTK_BOX(widget), label, FALSE, FALSE, 0); 01136 if (entry) 01137 gtk_box_pack_start(GTK_BOX(widget), entry, TRUE, TRUE, 0); 01138 break; 01139 case WIDGET_COMBO_BOX: 01140 widget = gtk_hbox_new(FALSE, 6); 01141 01142 GtkWidget *combo = NULL; 01143 create_cbox (& widgets[x], & label, & combo, domain); 01144 01145 if (label) 01146 gtk_box_pack_start(GTK_BOX(widget), label, FALSE, FALSE, 0); 01147 if (combo) 01148 gtk_box_pack_start(GTK_BOX(widget), combo, FALSE, FALSE, 0); 01149 break; 01150 case WIDGET_BOX: 01151 gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 0, 0, 0); 01152 01153 if (widgets[x].data.box.horizontal) { 01154 widget = gtk_hbox_new(FALSE, 0); 01155 } else { 01156 widget = gtk_vbox_new(FALSE, 0); 01157 } 01158 01159 create_widgets_with_domain ((GtkBox *) widget, 01160 widgets[x].data.box.elem, widgets[x].data.box.n_elem, domain); 01161 01162 if (widgets[x].data.box.frame) { 01163 GtkWidget *tmp; 01164 tmp = widget; 01165 01166 widget = gtk_frame_new (dgettext (domain, widgets[x].label)); 01167 gtk_container_add(GTK_CONTAINER(widget), tmp); 01168 } 01169 break; 01170 case WIDGET_NOTEBOOK: 01171 gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 6, 0, 0, 0); 01172 01173 widget = gtk_notebook_new(); 01174 01175 gint i; 01176 for (i = 0; i<widgets[x].data.notebook.n_tabs; i++) { 01177 GtkWidget *vbox; 01178 vbox = gtk_vbox_new(FALSE, 5); 01179 create_widgets_with_domain ((GtkBox *) vbox, 01180 widgets[x].data.notebook.tabs[i].settings, 01181 widgets[x].data.notebook.tabs[i].n_settings, domain); 01182 01183 gtk_notebook_append_page (GTK_NOTEBOOK (widget), vbox, 01184 gtk_label_new (dgettext (domain, 01185 widgets[x].data.notebook.tabs[i].name))); 01186 } 01187 break; 01188 case WIDGET_SEPARATOR: 01189 gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 6, 6, 0, 0); 01190 01191 if (widgets[x].data.separator.horizontal == TRUE) { 01192 widget = gtk_hseparator_new(); 01193 } else { 01194 widget = gtk_vseparator_new(); 01195 } 01196 break; 01197 default: 01198 break; 01199 } 01200 01201 if (widget && !gtk_widget_get_parent(widget)) 01202 gtk_container_add(GTK_CONTAINER(alignment), widget); 01203 if (widget && widgets[x].tooltip && widgets[x].type != WIDGET_SPIN_BTN) 01204 gtk_widget_set_tooltip_text (widget, dgettext (domain, 01205 widgets[x].tooltip)); 01206 } 01207 01208 } 01209 01210 static GtkWidget * 01211 create_titlestring_tag_menu(void) 01212 { 01213 GtkWidget *titlestring_tag_menu, *menu_item; 01214 guint i; 01215 01216 titlestring_tag_menu = gtk_menu_new(); 01217 for(i = 0; i < n_title_field_tags; i++) { 01218 menu_item = gtk_menu_item_new_with_label(_(title_field_tags[i].name)); 01219 gtk_menu_shell_append(GTK_MENU_SHELL(titlestring_tag_menu), menu_item); 01220 g_signal_connect(menu_item, "activate", 01221 G_CALLBACK(titlestring_tag_menu_callback), 01222 GINT_TO_POINTER(i)); 01223 }; 01224 gtk_widget_show_all(titlestring_tag_menu); 01225 01226 return titlestring_tag_menu; 01227 } 01228 01229 static void show_numbers_cb (GtkToggleButton * numbers, void * unused) 01230 { 01231 cfg.show_numbers_in_pl = gtk_toggle_button_get_active (numbers); 01232 01233 hook_call ("title change", NULL); 01234 01235 /* trigger playlist update */ 01236 gchar * t = playlist_get_title (playlist_get_active ()); 01237 playlist_set_title (playlist_get_active (), t); 01238 g_free (t); 01239 } 01240 01241 static void leading_zero_cb (GtkToggleButton * leading) 01242 { 01243 cfg.leading_zero = gtk_toggle_button_get_active (leading); 01244 01245 hook_call ("title change", NULL); 01246 01247 /* trigger playlist update */ 01248 gchar * t = playlist_get_title (playlist_get_active ()); 01249 playlist_set_title (playlist_get_active (), t); 01250 g_free (t); 01251 } 01252 01253 static void 01254 create_playlist_category(void) 01255 { 01256 GtkWidget *vbox5; 01257 GtkWidget *alignment55; 01258 GtkWidget *label60; 01259 GtkWidget *alignment56; 01260 GtkWidget *table6; 01261 GtkWidget *titlestring_help_button; 01262 GtkWidget *image1; 01263 GtkWidget *titlestring_cbox; 01264 GtkWidget *label62; 01265 GtkWidget *label61; 01266 GtkWidget *alignment85; 01267 GtkWidget *label84; 01268 GtkWidget *alignment86; 01269 GtkWidget *hbox9; 01270 GtkWidget *vbox34; 01271 GtkWidget *image8; 01272 GtkWidget *titlestring_tag_menu = create_titlestring_tag_menu(); 01273 GtkWidget * numbers_alignment, * numbers; 01274 01275 vbox5 = gtk_vbox_new (FALSE, 0); 01276 gtk_container_add ((GtkContainer *) category_notebook, vbox5); 01277 01278 create_widgets(GTK_BOX(vbox5), playlist_page_widgets, G_N_ELEMENTS(playlist_page_widgets)); 01279 01280 alignment55 = gtk_alignment_new (0.5, 0.5, 1, 1); 01281 gtk_box_pack_start (GTK_BOX (vbox5), alignment55, FALSE, FALSE, 0); 01282 gtk_alignment_set_padding ((GtkAlignment *) alignment55, 12, 3, 0, 0); 01283 01284 label60 = gtk_label_new (_("<b>Song Display</b>")); 01285 gtk_container_add (GTK_CONTAINER (alignment55), label60); 01286 gtk_label_set_use_markup (GTK_LABEL (label60), TRUE); 01287 gtk_misc_set_alignment (GTK_MISC (label60), 0, 0.5); 01288 01289 numbers_alignment = gtk_alignment_new (0, 0, 0, 0); 01290 gtk_alignment_set_padding ((GtkAlignment *) numbers_alignment, 0, 0, 12, 0); 01291 gtk_box_pack_start ((GtkBox *) vbox5, numbers_alignment, 0, 0, 3); 01292 01293 numbers = gtk_check_button_new_with_label (_("Show song numbers")); 01294 gtk_toggle_button_set_active ((GtkToggleButton *) numbers, 01295 cfg.show_numbers_in_pl); 01296 g_signal_connect ((GObject *) numbers, "toggled", (GCallback) 01297 show_numbers_cb, 0); 01298 gtk_container_add ((GtkContainer *) numbers_alignment, numbers); 01299 01300 numbers_alignment = gtk_alignment_new (0, 0, 0, 0); 01301 gtk_alignment_set_padding ((GtkAlignment *) numbers_alignment, 0, 0, 12, 0); 01302 gtk_box_pack_start ((GtkBox *) vbox5, numbers_alignment, 0, 0, 3); 01303 01304 numbers = gtk_check_button_new_with_label (_("Show leading zeroes (02:00 " 01305 "instead of 2:00)")); 01306 gtk_toggle_button_set_active ((GtkToggleButton *) numbers, cfg.leading_zero); 01307 g_signal_connect ((GObject *) numbers, "toggled", (GCallback) 01308 leading_zero_cb, 0); 01309 gtk_container_add ((GtkContainer *) numbers_alignment, numbers); 01310 01311 alignment56 = gtk_alignment_new (0.5, 0.5, 1, 1); 01312 gtk_box_pack_start (GTK_BOX (vbox5), alignment56, FALSE, FALSE, 0); 01313 gtk_alignment_set_padding (GTK_ALIGNMENT (alignment56), 0, 0, 12, 0); 01314 01315 table6 = gtk_table_new (2, 3, FALSE); 01316 gtk_container_add (GTK_CONTAINER (alignment56), table6); 01317 gtk_table_set_row_spacings (GTK_TABLE (table6), 4); 01318 gtk_table_set_col_spacings (GTK_TABLE (table6), 12); 01319 01320 titlestring_help_button = gtk_button_new (); 01321 gtk_table_attach (GTK_TABLE (table6), titlestring_help_button, 2, 3, 1, 2, 01322 (GtkAttachOptions) (0), 01323 (GtkAttachOptions) (0), 0, 0); 01324 01325 gtk_widget_set_can_focus (titlestring_help_button, FALSE); 01326 gtk_widget_set_tooltip_text (titlestring_help_button, _("Show information about titlestring format")); 01327 gtk_button_set_relief (GTK_BUTTON (titlestring_help_button), GTK_RELIEF_HALF); 01328 gtk_button_set_focus_on_click (GTK_BUTTON (titlestring_help_button), FALSE); 01329 01330 image1 = gtk_image_new_from_stock ("gtk-index", GTK_ICON_SIZE_BUTTON); 01331 gtk_container_add (GTK_CONTAINER (titlestring_help_button), image1); 01332 01333 titlestring_cbox = gtk_combo_box_text_new (); 01334 gtk_combo_box_set_active ((GtkComboBox *) titlestring_cbox, cfg.titlestring_preset); 01335 01336 gtk_table_attach (GTK_TABLE (table6), titlestring_cbox, 1, 3, 0, 1, 01337 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 01338 (GtkAttachOptions) (0), 0, 0); 01339 01340 gtk_combo_box_text_append_text ((GtkComboBoxText *) titlestring_cbox, _("TITLE")); 01341 gtk_combo_box_text_append_text ((GtkComboBoxText *) titlestring_cbox, _("ARTIST - TITLE")); 01342 gtk_combo_box_text_append_text ((GtkComboBoxText *) titlestring_cbox, _("ARTIST - ALBUM - TITLE")); 01343 gtk_combo_box_text_append_text ((GtkComboBoxText *) titlestring_cbox, _("ARTIST - ALBUM - TRACK. TITLE")); 01344 gtk_combo_box_text_append_text ((GtkComboBoxText *) titlestring_cbox, _("ARTIST [ ALBUM ] - TRACK. TITLE")); 01345 gtk_combo_box_text_append_text ((GtkComboBoxText *) titlestring_cbox, _("ALBUM - TITLE")); 01346 gtk_combo_box_text_append_text ((GtkComboBoxText *) titlestring_cbox, _("Custom")); 01347 01348 titlestring_entry = gtk_entry_new (); 01349 gtk_entry_set_text ((GtkEntry *) titlestring_entry, cfg.gentitle_format); 01350 gtk_widget_set_sensitive (titlestring_entry, cfg.titlestring_preset == n_titlestring_presets); 01351 gtk_table_attach (GTK_TABLE (table6), titlestring_entry, 1, 2, 1, 2, 01352 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 01353 (GtkAttachOptions) (0), 0, 0); 01354 01355 label62 = gtk_label_new (_("Custom string:")); 01356 gtk_table_attach (GTK_TABLE (table6), label62, 0, 1, 1, 2, 01357 (GtkAttachOptions) (0), 01358 (GtkAttachOptions) (0), 0, 0); 01359 gtk_label_set_justify (GTK_LABEL (label62), GTK_JUSTIFY_RIGHT); 01360 gtk_misc_set_alignment (GTK_MISC (label62), 1, 0.5); 01361 01362 label61 = gtk_label_new (_("Title format:")); 01363 gtk_table_attach (GTK_TABLE (table6), label61, 0, 1, 0, 1, 01364 (GtkAttachOptions) (0), 01365 (GtkAttachOptions) (0), 0, 0); 01366 gtk_label_set_justify (GTK_LABEL (label61), GTK_JUSTIFY_RIGHT); 01367 gtk_misc_set_alignment (GTK_MISC (label61), 1, 0.5); 01368 01369 alignment85 = gtk_alignment_new (0.5, 0.5, 1, 1); 01370 gtk_box_pack_start (GTK_BOX (vbox5), alignment85, FALSE, FALSE, 0); 01371 gtk_alignment_set_padding (GTK_ALIGNMENT (alignment85), 12, 12, 0, 0); 01372 01373 label84 = gtk_label_new (_("<b>Popup Information</b>")); 01374 gtk_container_add (GTK_CONTAINER (alignment85), label84); 01375 gtk_label_set_use_markup (GTK_LABEL (label84), TRUE); 01376 gtk_misc_set_alignment (GTK_MISC (label84), 0, 0.5); 01377 01378 alignment86 = gtk_alignment_new (0.5, 0.5, 1, 1); 01379 gtk_box_pack_start (GTK_BOX (vbox5), alignment86, FALSE, FALSE, 0); 01380 gtk_alignment_set_padding (GTK_ALIGNMENT (alignment86), 0, 0, 12, 0); 01381 01382 hbox9 = gtk_hbox_new (FALSE, 12); 01383 gtk_container_add (GTK_CONTAINER (alignment86), hbox9); 01384 01385 vbox34 = gtk_vbox_new (FALSE, 0); 01386 gtk_box_pack_start (GTK_BOX (hbox9), vbox34, TRUE, TRUE, 0); 01387 01388 filepopupbutton = gtk_check_button_new_with_mnemonic (_("Show popup information for playlist entries")); 01389 gtk_widget_set_tooltip_text (filepopupbutton, _("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.")); 01390 gtk_toggle_button_set_active ((GtkToggleButton *) filepopupbutton, cfg.show_filepopup_for_tuple); 01391 gtk_box_pack_start ((GtkBox *) vbox34, filepopupbutton, TRUE, FALSE, 0); 01392 01393 filepopup_for_tuple_settings_button = gtk_button_new (); 01394 gtk_widget_set_sensitive (filepopup_for_tuple_settings_button, cfg.show_filepopup_for_tuple); 01395 gtk_box_pack_start (GTK_BOX (hbox9), filepopup_for_tuple_settings_button, FALSE, FALSE, 0); 01396 01397 gtk_widget_set_can_focus (filepopup_for_tuple_settings_button, FALSE); 01398 gtk_widget_set_tooltip_text (filepopup_for_tuple_settings_button, _("Edit settings for popup information")); 01399 gtk_button_set_relief (GTK_BUTTON (filepopup_for_tuple_settings_button), GTK_RELIEF_HALF); 01400 01401 image8 = gtk_image_new_from_stock ("gtk-properties", GTK_ICON_SIZE_BUTTON); 01402 gtk_container_add (GTK_CONTAINER (filepopup_for_tuple_settings_button), image8); 01403 01404 01405 01406 g_signal_connect (filepopupbutton, "toggled", 01407 G_CALLBACK(on_show_filepopup_for_tuple_toggled), 01408 NULL); 01409 g_signal_connect(G_OBJECT(filepopup_for_tuple_settings_button), "clicked", 01410 G_CALLBACK(on_filepopup_for_tuple_settings_clicked), 01411 NULL); 01412 01413 g_signal_connect(titlestring_cbox, "changed", 01414 G_CALLBACK(on_titlestring_cbox_changed), 01415 titlestring_entry); 01416 01417 g_signal_connect(titlestring_cbox, "changed", 01418 G_CALLBACK(on_titlestring_cbox_changed), 01419 titlestring_help_button); 01420 g_signal_connect(titlestring_help_button, "clicked", 01421 G_CALLBACK(on_titlestring_help_button_clicked), 01422 titlestring_tag_menu); 01423 01424 g_signal_connect(G_OBJECT(titlestring_entry), "changed", 01425 G_CALLBACK(on_titlestring_entry_changed), 01426 NULL); 01427 01428 /* Create window for filepopup settings */ 01429 create_filepopup_settings(); 01430 } 01431 01432 static GtkWidget * output_config_button, * output_about_button; 01433 01434 static gboolean output_enum_cb (PluginHandle * plugin, GList * * list) 01435 { 01436 * list = g_list_prepend (* list, plugin); 01437 return TRUE; 01438 } 01439 01440 static GList * output_get_list (void) 01441 { 01442 static GList * list = NULL; 01443 01444 if (list == NULL) 01445 { 01446 plugin_for_each (PLUGIN_TYPE_OUTPUT, (PluginForEachFunc) output_enum_cb, 01447 & list); 01448 list = g_list_reverse (list); 01449 } 01450 01451 return list; 01452 } 01453 01454 static void output_combo_update (GtkComboBox * combo) 01455 { 01456 PluginHandle * plugin = plugin_get_current (PLUGIN_TYPE_OUTPUT); 01457 gtk_combo_box_set_active (combo, g_list_index (output_get_list (), plugin)); 01458 gtk_widget_set_sensitive (output_config_button, plugin_has_configure (plugin)); 01459 gtk_widget_set_sensitive (output_about_button, plugin_has_about (plugin)); 01460 } 01461 01462 static void output_combo_changed (GtkComboBox * combo) 01463 { 01464 PluginHandle * plugin = g_list_nth_data (output_get_list (), 01465 gtk_combo_box_get_active (combo)); 01466 g_return_if_fail (plugin != NULL); 01467 01468 plugin_enable (plugin, TRUE); 01469 output_combo_update (combo); 01470 } 01471 01472 static void output_combo_fill (GtkComboBox * combo) 01473 { 01474 for (GList * node = output_get_list (); node != NULL; node = node->next) 01475 gtk_combo_box_text_append_text ((GtkComboBoxText *) combo, 01476 plugin_get_name (node->data)); 01477 } 01478 01479 static void output_do_config (void) 01480 { 01481 OutputPlugin * op = plugin_get_header (output_plugin_get_current ()); 01482 g_return_if_fail (op != NULL); 01483 if (op->configure != NULL) 01484 op->configure (); 01485 } 01486 01487 static void output_do_about (void) 01488 { 01489 OutputPlugin * op = plugin_get_header (output_plugin_get_current ()); 01490 g_return_if_fail (op != NULL); 01491 if (op->about != NULL) 01492 op->about (); 01493 } 01494 01495 static void * create_output_plugin_box (void) 01496 { 01497 GtkWidget * hbox1 = gtk_hbox_new (FALSE, 6); 01498 gtk_box_pack_start ((GtkBox *) hbox1, gtk_label_new (_("Output plugin:")), FALSE, FALSE, 0); 01499 01500 GtkWidget * vbox = gtk_vbox_new (FALSE, 6); 01501 gtk_box_pack_start ((GtkBox *) hbox1, vbox, FALSE, FALSE, 0); 01502 01503 GtkWidget * hbox2 = gtk_hbox_new (FALSE, 6); 01504 gtk_box_pack_start ((GtkBox *) vbox, hbox2, FALSE, FALSE, 0); 01505 01506 GtkWidget * output_plugin_cbox = gtk_combo_box_text_new (); 01507 gtk_box_pack_start ((GtkBox *) hbox2, output_plugin_cbox, FALSE, FALSE, 0); 01508 01509 GtkWidget * hbox3 = gtk_hbox_new (FALSE, 6); 01510 gtk_box_pack_start ((GtkBox *) vbox, hbox3, FALSE, FALSE, 0); 01511 01512 output_config_button = gtk_button_new_from_stock (GTK_STOCK_PREFERENCES); 01513 gtk_box_pack_start ((GtkBox *) hbox3, output_config_button, FALSE, FALSE, 0); 01514 01515 output_about_button = gtk_button_new_from_stock (GTK_STOCK_ABOUT); 01516 gtk_box_pack_start ((GtkBox *) hbox3, output_about_button, FALSE, FALSE, 0); 01517 01518 output_combo_fill ((GtkComboBox *) output_plugin_cbox); 01519 output_combo_update ((GtkComboBox *) output_plugin_cbox); 01520 01521 g_signal_connect (output_plugin_cbox, "changed", (GCallback) output_combo_changed, NULL); 01522 g_signal_connect (output_config_button, "clicked", (GCallback) output_do_config, NULL); 01523 g_signal_connect (output_about_button, "clicked", (GCallback) output_do_about, NULL); 01524 01525 return hbox1; 01526 } 01527 01528 static void create_audio_category (void) 01529 { 01530 GtkWidget * audio_page_vbox = gtk_vbox_new (FALSE, 0); 01531 create_widgets ((GtkBox *) audio_page_vbox, audio_page_widgets, G_N_ELEMENTS (audio_page_widgets)); 01532 gtk_container_add ((GtkContainer *) category_notebook, audio_page_vbox); 01533 } 01534 01535 static void 01536 create_connectivity_category(void) 01537 { 01538 GtkWidget *connectivity_page_vbox; 01539 GtkWidget *vbox29; 01540 01541 connectivity_page_vbox = gtk_vbox_new (FALSE, 0); 01542 gtk_container_add (GTK_CONTAINER (category_notebook), connectivity_page_vbox); 01543 01544 vbox29 = gtk_vbox_new (FALSE, 0); 01545 gtk_box_pack_start (GTK_BOX (connectivity_page_vbox), vbox29, TRUE, TRUE, 0); 01546 01547 create_widgets(GTK_BOX(vbox29), connectivity_page_widgets, G_N_ELEMENTS(connectivity_page_widgets)); 01548 } 01549 01550 static void create_plugin_category (void) 01551 { 01552 GtkWidget * notebook = gtk_notebook_new (); 01553 gtk_container_add ((GtkContainer *) category_notebook, notebook); 01554 01555 gint types[] = {PLUGIN_TYPE_TRANSPORT, PLUGIN_TYPE_PLAYLIST, 01556 PLUGIN_TYPE_INPUT, PLUGIN_TYPE_EFFECT, PLUGIN_TYPE_VIS, PLUGIN_TYPE_GENERAL}; 01557 const gchar * names[] = {N_("Transport"), N_("Playlist"), N_("Input"), 01558 N_("Effect"), N_("Visualization"), N_("General")}; 01559 01560 for (gint i = 0; i < G_N_ELEMENTS (types); i ++) 01561 gtk_notebook_append_page ((GtkNotebook *) notebook, plugin_view_new 01562 (types[i]), gtk_label_new (_(names[i]))); 01563 } 01564 01565 static gboolean 01566 prefswin_destroy(GtkWidget *window, GdkEvent *event, gpointer data) 01567 { 01568 prefswin = NULL; 01569 category_notebook = NULL; 01570 gtk_widget_destroy(filepopup_settings); 01571 filepopup_settings = NULL; 01572 gtk_widget_destroy(window); 01573 return TRUE; 01574 } 01575 01576 /* GtkWidget * * create_prefs_window (void) */ 01577 void * * create_prefs_window (void) 01578 { 01579 gchar *aud_version_string; 01580 01581 GtkWidget *vbox; 01582 GtkWidget *hbox1; 01583 GtkWidget *scrolledwindow6; 01584 GtkWidget *hseparator1; 01585 GtkWidget *hbox4; 01586 GtkWidget *audversionlabel; 01587 GtkWidget *prefswin_button_box; 01588 GtkWidget *hbox11; 01589 GtkWidget *image10; 01590 GtkWidget *close; 01591 GtkAccelGroup *accel_group; 01592 01593 accel_group = gtk_accel_group_new (); 01594 01595 prefswin = gtk_window_new (GTK_WINDOW_TOPLEVEL); 01596 gtk_window_set_type_hint (GTK_WINDOW (prefswin), GDK_WINDOW_TYPE_HINT_DIALOG); 01597 gtk_container_set_border_width (GTK_CONTAINER (prefswin), 12); 01598 gtk_window_set_title (GTK_WINDOW (prefswin), _("Audacious Preferences")); 01599 gtk_window_set_position (GTK_WINDOW (prefswin), GTK_WIN_POS_CENTER); 01600 gtk_window_set_default_size (GTK_WINDOW (prefswin), 680, 400); 01601 01602 vbox = gtk_vbox_new (FALSE, 0); 01603 gtk_container_add (GTK_CONTAINER (prefswin), vbox); 01604 01605 hbox1 = gtk_hbox_new (FALSE, 8); 01606 gtk_box_pack_start (GTK_BOX (vbox), hbox1, TRUE, TRUE, 0); 01607 01608 scrolledwindow6 = gtk_scrolled_window_new (NULL, NULL); 01609 gtk_box_pack_start (GTK_BOX (hbox1), scrolledwindow6, FALSE, FALSE, 0); 01610 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow6), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); 01611 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow6), GTK_SHADOW_IN); 01612 01613 category_treeview = gtk_tree_view_new (); 01614 gtk_container_add (GTK_CONTAINER (scrolledwindow6), category_treeview); 01615 gtk_widget_set_size_request (scrolledwindow6, 168, -1); 01616 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (category_treeview), FALSE); 01617 01618 category_notebook = gtk_notebook_new (); 01619 gtk_box_pack_start (GTK_BOX (hbox1), category_notebook, TRUE, TRUE, 0); 01620 01621 gtk_widget_set_can_focus (category_notebook, FALSE); 01622 gtk_notebook_set_show_tabs (GTK_NOTEBOOK (category_notebook), FALSE); 01623 gtk_notebook_set_show_border (GTK_NOTEBOOK (category_notebook), FALSE); 01624 gtk_notebook_set_scrollable (GTK_NOTEBOOK (category_notebook), TRUE); 01625 01626 create_audio_category(); 01627 create_connectivity_category(); 01628 create_playlist_category(); 01629 create_plugin_category(); 01630 01631 hseparator1 = gtk_hseparator_new (); 01632 gtk_box_pack_start (GTK_BOX (vbox), hseparator1, FALSE, FALSE, 6); 01633 01634 hbox4 = gtk_hbox_new (FALSE, 0); 01635 gtk_box_pack_start (GTK_BOX (vbox), hbox4, FALSE, FALSE, 0); 01636 01637 audversionlabel = gtk_label_new (""); 01638 gtk_box_pack_start (GTK_BOX (hbox4), audversionlabel, FALSE, FALSE, 0); 01639 gtk_label_set_use_markup (GTK_LABEL (audversionlabel), TRUE); 01640 01641 prefswin_button_box = gtk_hbutton_box_new (); 01642 gtk_box_pack_start (GTK_BOX (hbox4), prefswin_button_box, TRUE, TRUE, 0); 01643 gtk_button_box_set_layout (GTK_BUTTON_BOX (prefswin_button_box), GTK_BUTTONBOX_END); 01644 gtk_box_set_spacing (GTK_BOX (prefswin_button_box), 6); 01645 01646 hbox11 = gtk_hbox_new (FALSE, 2); 01647 01648 image10 = gtk_image_new_from_stock ("gtk-refresh", GTK_ICON_SIZE_BUTTON); 01649 gtk_box_pack_start (GTK_BOX (hbox11), image10, FALSE, FALSE, 0); 01650 01651 close = gtk_button_new_from_stock ("gtk-close"); 01652 gtk_container_add (GTK_CONTAINER (prefswin_button_box), close); 01653 gtk_widget_set_can_default(close, TRUE); 01654 gtk_widget_add_accelerator (close, "clicked", accel_group, 01655 GDK_Escape, (GdkModifierType) 0, 01656 GTK_ACCEL_VISIBLE); 01657 01658 01659 gtk_window_add_accel_group (GTK_WINDOW (prefswin), accel_group); 01660 01661 /* connect signals */ 01662 g_signal_connect(G_OBJECT(prefswin), "delete_event", 01663 G_CALLBACK(prefswin_destroy), 01664 NULL); 01665 g_signal_connect_swapped(G_OBJECT(close), "clicked", 01666 G_CALLBACK(prefswin_destroy), 01667 prefswin); 01668 01669 /* create category view */ 01670 fill_category_list ((GtkTreeView *) category_treeview, (GtkNotebook *) category_notebook); 01671 01672 /* audacious version label */ 01673 01674 aud_version_string = g_strdup_printf 01675 ("<span size='small'>%s (%s)</span>", "Audacious " PACKAGE_VERSION, 01676 BUILDSTAMP); 01677 01678 gtk_label_set_markup( GTK_LABEL(audversionlabel) , aud_version_string ); 01679 g_free(aud_version_string); 01680 gtk_widget_show_all(vbox); 01681 01682 return & prefswin; 01683 } 01684 01685 void 01686 destroy_prefs_window(void) 01687 { 01688 prefswin_destroy(prefswin, NULL, NULL); 01689 } 01690 01691 void show_prefs_window (void) 01692 { 01693 if (! prefswin) 01694 create_prefs_window (); 01695 01696 gtk_window_present ((GtkWindow *) prefswin); 01697 } 01698 01699 void 01700 hide_prefs_window(void) 01701 { 01702 g_return_if_fail(prefswin); 01703 gtk_widget_hide(GTK_WIDGET(prefswin)); 01704 } 01705 01706 static void prefswin_page_queue_new (GtkWidget * container, const gchar * name, 01707 const gchar * imgurl) 01708 { 01709 CategoryQueueEntry *ent = g_new0(CategoryQueueEntry, 1); 01710 01711 ent->container = container; 01712 ent->pg_name = name; 01713 ent->img_url = imgurl; 01714 01715 if (category_queue) 01716 ent->next = category_queue; 01717 01718 category_queue = ent; 01719 } 01720 01721 static void 01722 prefswin_page_queue_destroy(CategoryQueueEntry *ent) 01723 { 01724 category_queue = ent->next; 01725 g_free(ent); 01726 } 01727 01728 /* 01729 * Public APIs for adding new pages to the prefs window. 01730 * 01731 * Basically, the concept here is that third party components can register themselves in the root 01732 * preferences window. 01733 * 01734 * From a usability standpoint this makes the application look more "united", instead of cluttered 01735 * and malorganised. Hopefully this option will be used further in the future. 01736 * 01737 * - nenolod 01738 */ 01739 /* gint prefswin_page_new (GtkWidget * container, const gchar * name, 01740 const gchar * imgurl) */ 01741 gint prefswin_page_new (void * container, const gchar * name, const gchar * 01742 imgurl) 01743 { 01744 GtkTreeModel *model; 01745 GtkTreeIter iter; 01746 GdkPixbuf *img = NULL; 01747 GtkTreeView *treeview = GTK_TREE_VIEW(category_treeview); 01748 gint id; 01749 01750 if (treeview == NULL || category_notebook == NULL) 01751 { 01752 prefswin_page_queue_new(container, name, imgurl); 01753 return -1; 01754 } 01755 01756 model = gtk_tree_view_get_model(treeview); 01757 01758 if (model == NULL) 01759 { 01760 prefswin_page_queue_new(container, name, imgurl); 01761 return -1; 01762 } 01763 01764 /* Make sure the widgets are visible. */ 01765 gtk_widget_show(container); 01766 id = gtk_notebook_append_page(GTK_NOTEBOOK(category_notebook), container, NULL); 01767 01768 if (id == -1) 01769 return -1; 01770 01771 if (imgurl != NULL) 01772 img = gdk_pixbuf_new_from_file(imgurl, NULL); 01773 01774 gtk_list_store_append(GTK_LIST_STORE(model), &iter); 01775 gtk_list_store_set(GTK_LIST_STORE(model), &iter, 01776 CATEGORY_VIEW_COL_ICON, img, 01777 CATEGORY_VIEW_COL_NAME, 01778 name, CATEGORY_VIEW_COL_ID, id, -1); 01779 01780 if (img != NULL) 01781 g_object_unref(img); 01782 01783 return id; 01784 } 01785 01786 void 01787 prefswin_page_destroy(GtkWidget *container) 01788 { 01789 GtkTreeModel *model; 01790 GtkTreeIter iter; 01791 GtkTreeView *treeview = GTK_TREE_VIEW(category_treeview); 01792 gboolean ret; 01793 gint id; 01794 gint index = -1; 01795 01796 if (category_notebook == NULL || treeview == NULL || container == NULL) 01797 return; 01798 01799 id = gtk_notebook_page_num(GTK_NOTEBOOK(category_notebook), container); 01800 01801 if (id == -1) 01802 return; 01803 01804 gtk_notebook_remove_page(GTK_NOTEBOOK(category_notebook), id); 01805 01806 model = gtk_tree_view_get_model(treeview); 01807 01808 if (model == NULL) 01809 return; 01810 01811 ret = gtk_tree_model_get_iter_first(model, &iter); 01812 01813 while (ret == TRUE) 01814 { 01815 gtk_tree_model_get(model, &iter, CATEGORY_VIEW_COL_ID, &index, -1); 01816 01817 if (index == id) 01818 { 01819 gtk_list_store_remove(GTK_LIST_STORE(model), &iter); 01820 ret = gtk_tree_model_get_iter_first(model, &iter); 01821 continue; 01822 } 01823 01824 if (index > id) 01825 { 01826 index--; 01827 gtk_list_store_set(GTK_LIST_STORE(model), &iter, CATEGORY_VIEW_COL_ID, index, -1); 01828 } 01829 01830 ret = gtk_tree_model_iter_next(model, &iter); 01831 } 01832 } 01833 01834 static void sw_volume_toggled (void) 01835 { 01836 gint vol[2]; 01837 01838 if (cfg.software_volume_control) 01839 { 01840 vol[0] = cfg.sw_volume_left; 01841 vol[1] = cfg.sw_volume_right; 01842 } 01843 else 01844 playback_get_volume (& vol[0], & vol[1]); 01845 01846 hook_call ("volume set", vol); 01847 }