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