1 /*****************************************************************************
2 * gtk_preferences.c: functions to handle the preferences dialog box.
3 *****************************************************************************
4 * Copyright (C) 2001-2004 VideoLAN
5 * $Id: preferences.c,v 1.11 2004/01/25 18:34:55 gbazin Exp $
7 * Authors: Gildas Bazin <gbazin@netcourrier.com>
8 * Loïc Minier <lool@via.ecp.fr>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
23 *****************************************************************************/
25 /*****************************************************************************
26 * Preamble: Our main job is to build a nice interface from the modules config
27 * structure. Once this is done, we need to track each change made by the
28 * user to the data contained in this interface so that when/if he decides to
29 * apply his changes we can quickly commit them into the modules config
30 * structure. (for this last task we use a GHashTable to accumulate the
31 * changes. To commit them, we then just have to circle through it )
33 *****************************************************************************/
34 #include <sys/types.h> /* off_t */
40 #ifdef MODULE_NAME_IS_gnome
48 #include "gtk_support.h"
51 #include "preferences.h"
54 static void GtkCreateConfigDialog( char *, intf_thread_t * );
56 static void GtkConfigOk ( GtkButton *, gpointer );
57 static void GtkConfigApply ( GtkButton *, gpointer );
58 static void GtkConfigCancel ( GtkButton *, gpointer );
59 static void GtkConfigSave ( GtkButton *, gpointer );
61 static void GtkConfigDialogDestroyed ( GtkObject *, gpointer );
63 static void GtkStringChanged ( GtkEditable *, gpointer );
64 static void GtkIntChanged ( GtkEditable *, gpointer );
65 static void GtkIntRangedChanged ( GtkEditable *, gpointer );
66 static void GtkFloatChanged ( GtkEditable *, gpointer );
67 static void GtkFloatRangedChanged ( GtkEditable *, gpointer );
68 static void GtkBoolChanged ( GtkToggleButton *, gpointer );
70 static void GtkFreeHashTable ( GtkObject *object );
71 static void GtkFreeHashValue ( gpointer, gpointer, gpointer );
72 static gboolean GtkSaveHashValue ( gpointer, gpointer, gpointer );
74 static void GtkModuleConfigure ( GtkButton *, gpointer );
75 static void GtkModuleSelected ( GtkButton *, gpointer );
76 static void GtkModuleHighlighted ( GtkCList *, int, int, GdkEventButton *,
79 /****************************************************************************
80 * Callback for menuitems: display configuration interface window
81 ****************************************************************************/
82 void GtkPreferencesShow( GtkMenuItem * menuitem, gpointer user_data )
84 intf_thread_t * p_intf;
86 p_intf = GtkGetIntf( menuitem );
88 GtkCreateConfigDialog( "main", p_intf );
91 /****************************************************************************
92 * GtkCreateConfigDialog: dynamically creates the configuration dialog
93 * box from all the configuration data provided by the selected module.
94 ****************************************************************************/
96 /* create a new tooltipped area */
97 #define TOOLTIP( text ) \
98 /* create an event box to catch some events */ \
99 item_event_box = gtk_event_box_new(); \
100 /* add a tooltip on mouseover */ \
101 gtk_tooltips_set_tip( p_intf->p_sys->p_tooltips, \
102 item_event_box, text, "" ); \
103 gtk_container_set_border_width( GTK_CONTAINER(item_event_box), 4 );
105 /* draws a right aligned label in side of a widget */
106 #define LABEL_AND_WIDGET( label_text, widget, tooltip ) \
107 gtk_table_resize( GTK_TABLE(category_table), ++rows, 2 ); \
108 item_align = gtk_alignment_new( 1, .5, 0, 0 ); \
109 item_label = gtk_label_new( label_text ); \
110 gtk_container_add( GTK_CONTAINER(item_align), item_label ); \
111 gtk_table_attach_defaults( GTK_TABLE(category_table), item_align, \
112 0, 1, rows - 1, rows ); \
113 item_align = gtk_alignment_new( 0, .5, .5, 0 ); \
114 gtk_container_add( GTK_CONTAINER(item_align), widget ); \
116 gtk_container_add( GTK_CONTAINER(item_event_box), item_align ); \
117 gtk_table_attach_defaults( GTK_TABLE(category_table), item_event_box, \
118 1, 2, rows - 1, rows );
120 static void GtkCreateConfigDialog( char *psz_module_name,
121 intf_thread_t *p_intf )
123 module_t *p_parser = NULL;
125 module_config_t *p_item;
126 vlc_bool_t b_advanced = config_GetInt( p_intf, "advanced" );
131 GHashTable *config_hash_table;
133 GtkWidget *item_event_box;
135 GtkWidget *config_dialog;
136 GtkWidget *config_dialog_vbox;
137 GtkWidget *config_notebook;
139 GtkWidget *category_table = NULL;
140 GtkWidget *category_label = NULL;
142 #ifndef MODULE_NAME_IS_gnome
143 GtkWidget *dialog_action_area;
146 GtkWidget *ok_button;
147 GtkWidget *apply_button;
148 GtkWidget *save_button;
149 GtkWidget *cancel_button;
151 GtkWidget *item_align;
152 GtkWidget *item_frame;
153 GtkWidget *item_hbox;
154 GtkWidget *item_label;
155 GtkWidget *item_vbox;
156 GtkWidget *item_combo;
157 GtkWidget *string_entry;
158 GtkWidget *integer_spinbutton;
159 GtkWidget *integer_slider;
160 GtkWidget *float_spinbutton;
161 GtkWidget *float_slider;
163 GtkWidget *bool_checkbutton;
164 GtkWidget *module_clist;
165 GtkWidget *module_config_button;
166 GtkWidget *module_select_button;
168 gint category_max_height;
170 /* Check if the dialog box is already opened because we don't want to
171 * duplicate identical dialog windows. */
172 config_dialog = (GtkWidget *)gtk_object_get_data(
173 GTK_OBJECT(p_intf->p_sys->p_window), psz_module_name );
176 /* Yeah it was open */
177 gtk_widget_grab_focus( config_dialog );
182 /* Look for the selected module */
183 p_list = vlc_list_find( p_intf, VLC_OBJECT_MODULE, FIND_ANYWHERE );
185 for( i_index = 0; i_index < p_list->i_count; i_index++ )
187 p_parser = (module_t *)p_list->p_values[i_index].p_object ;
190 && !strcmp( psz_module_name, p_parser->psz_object_name ) )
196 if( !p_parser || i_index == p_list->i_count )
198 vlc_list_release( p_list );
202 /* We found it, now we can start building its configuration interface */
203 /* Create the configuration dialog box */
205 #ifdef MODULE_NAME_IS_gnome
206 config_dialog = gnome_dialog_new( p_parser->psz_longname, NULL );
207 config_dialog_vbox = GNOME_DIALOG(config_dialog)->vbox;
209 config_dialog = gtk_dialog_new();
210 gtk_window_set_title( GTK_WINDOW(config_dialog),
211 p_parser->psz_longname );
212 config_dialog_vbox = GTK_DIALOG(config_dialog)->vbox;
215 gtk_object_set_data( GTK_OBJECT(config_dialog), "p_intf", p_intf );
217 category_max_height = config_GetInt( p_intf, MODULE_STRING "-prefs-maxh" );
219 gtk_window_set_policy( GTK_WINDOW(config_dialog), TRUE, TRUE, FALSE );
220 gtk_container_set_border_width( GTK_CONTAINER(config_dialog_vbox), 0 );
222 /* Create our config hash table and associate it with the dialog box */
223 config_hash_table = g_hash_table_new( NULL, NULL );
224 gtk_object_set_data( GTK_OBJECT(config_dialog),
225 "config_hash_table", config_hash_table );
227 /* Create notebook */
228 config_notebook = gtk_notebook_new();
229 gtk_notebook_set_scrollable( GTK_NOTEBOOK(config_notebook), TRUE );
230 gtk_container_add( GTK_CONTAINER(config_dialog_vbox), config_notebook );
232 /* Enumerate config options and add corresponding config boxes */
233 p_item = p_parser->p_config;
237 if( p_item->b_advanced && !b_advanced ) continue;
239 if( p_item->i_type == CONFIG_HINT_CATEGORY ||
240 p_item->i_type == CONFIG_HINT_END ||
244 * Before we start building the interface for the new category, we
245 * must close/finish the previous one we were generating.
249 GtkWidget *_scrolled_window;
250 GtkWidget *_viewport;
252 GtkRequisition _requisition;
254 /* create a vbox to deal with EXPAND/FILL issues in the
255 * notebook page, and pack it with the previously generated
257 _vbox = gtk_vbox_new( FALSE, 0 );
258 gtk_container_set_border_width( GTK_CONTAINER(_vbox), 4 );
259 gtk_box_pack_start( GTK_BOX(_vbox), category_table,
262 /* create a new scrolled window that will contain all of the
264 _scrolled_window = gtk_scrolled_window_new( NULL, NULL );
265 gtk_scrolled_window_set_policy(
266 GTK_SCROLLED_WINDOW(_scrolled_window), GTK_POLICY_NEVER,
267 GTK_POLICY_AUTOMATIC );
268 /* add scrolled window as a notebook page */
269 gtk_notebook_append_page( GTK_NOTEBOOK(config_notebook),
270 _scrolled_window, category_label );
271 /* pack the vbox into the scrolled window */
272 _viewport = gtk_viewport_new( NULL, NULL );
273 gtk_viewport_set_shadow_type( GTK_VIEWPORT(_viewport),
275 gtk_container_add( GTK_CONTAINER(_viewport), _vbox );
276 gtk_container_add( GTK_CONTAINER(_scrolled_window),
279 /* set the size of the scrolled window to the size of the
281 gtk_widget_show_all( _vbox );
282 gtk_widget_size_request( _vbox, &_requisition );
283 if( _requisition.height > category_max_height )
284 gtk_widget_set_usize( _scrolled_window, -1,
285 category_max_height );
287 gtk_widget_set_usize( _scrolled_window, -1,
288 _requisition.height );
293 * Now we can start taking care of the new category
296 if( p_item->i_type != CONFIG_HINT_END )
298 /* create a new table for right-left alignment of children */
299 category_table = gtk_table_new( 0, 0, FALSE );
300 gtk_table_set_col_spacings( GTK_TABLE(category_table), 4 );
303 /* create a new category label */
304 if( p_item->i_type == CONFIG_HINT_CATEGORY )
305 category_label = gtk_label_new( p_item->psz_text );
307 category_label = gtk_label_new( p_parser->psz_longname );
311 switch( p_item->i_type )
314 case CONFIG_ITEM_MODULE:
316 item_frame = gtk_frame_new( p_item->psz_text );
318 gtk_table_resize( GTK_TABLE(category_table), ++rows, 2 );
319 gtk_table_attach_defaults( GTK_TABLE(category_table), item_frame,
320 0, 2, rows - 1, rows );
322 item_vbox = gtk_vbox_new( FALSE, 4 );
323 gtk_container_add( GTK_CONTAINER(item_frame), item_vbox );
325 /* create a new clist widget */
327 gchar * titles[] = { N_("Name"), N_("Description") };
328 titles[0] = _(titles[0]);
329 titles[1] = _(titles[1]);
331 module_clist = gtk_clist_new_with_titles( 2, titles );
333 gtk_object_set_data( GTK_OBJECT(module_clist), "p_intf", p_intf );
334 gtk_clist_column_titles_passive( GTK_CLIST(module_clist) );
335 gtk_clist_set_selection_mode( GTK_CLIST(module_clist),
336 GTK_SELECTION_SINGLE);
337 gtk_container_add( GTK_CONTAINER(item_vbox), module_clist );
339 /* build a list of available modules */
343 for( i_index = 0; i_index < p_list->i_count; i_index++ )
345 p_parser = (module_t *)p_list->p_values[i_index].p_object ;
347 if( !strcmp( p_parser->psz_capability,
350 entry[0] = p_parser->psz_object_name;
351 entry[1] = p_parser->psz_longname;
352 gtk_clist_append( GTK_CLIST(module_clist), entry );
357 gtk_clist_set_column_auto_resize( GTK_CLIST(module_clist),
359 gtk_clist_set_column_auto_resize( GTK_CLIST(module_clist),
362 /* connect signals to the modules list */
363 gtk_signal_connect( GTK_OBJECT(module_clist), "select_row",
364 GTK_SIGNAL_FUNC(GtkModuleHighlighted),
367 /* hbox holding the "select" and "configure" buttons */
368 item_hbox = gtk_hbox_new( FALSE, 4 );
369 gtk_container_add( GTK_CONTAINER(item_vbox), item_hbox);
371 /* add configure button */
372 module_config_button =
373 gtk_button_new_with_label( _("Configure") );
374 gtk_widget_set_sensitive( module_config_button, FALSE );
375 gtk_container_add( GTK_CONTAINER(item_hbox),
376 module_config_button );
377 gtk_object_set_data( GTK_OBJECT(module_config_button),
379 gtk_object_set_data( GTK_OBJECT(module_clist),
380 "config_button", module_config_button );
382 /* add select button */
383 module_select_button =
384 gtk_button_new_with_label( _("Select") );
385 gtk_container_add( GTK_CONTAINER(item_hbox),
386 module_select_button );
387 /* add a tooltip on mouseover */
388 gtk_tooltips_set_tip( p_intf->p_sys->p_tooltips,
389 module_select_button,
390 p_item->psz_longtext, "" );
392 /* hbox holding the "selected" label and text input */
393 item_hbox = gtk_hbox_new( FALSE, 4 );
394 gtk_container_add( GTK_CONTAINER(item_vbox), item_hbox);
396 item_label = gtk_label_new( _("Selected:") );
397 gtk_container_add( GTK_CONTAINER(item_hbox), item_label );
399 /* add input box with default value */
400 string_entry = gtk_entry_new();
401 gtk_object_set_data( GTK_OBJECT(module_clist),
402 "module_entry", string_entry );
403 gtk_container_add( GTK_CONTAINER(item_hbox), string_entry );
404 vlc_mutex_lock( p_item->p_lock );
405 gtk_entry_set_text( GTK_ENTRY(string_entry),
406 p_item->psz_value ? p_item->psz_value : "" );
407 vlc_mutex_unlock( p_item->p_lock );
408 /* add a tooltip on mouseover */
409 gtk_tooltips_set_tip( p_intf->p_sys->p_tooltips,
410 string_entry, p_item->psz_longtext, "" );
412 /* connect signals to the buttons */
413 gtk_signal_connect( GTK_OBJECT(module_config_button), "clicked",
414 GTK_SIGNAL_FUNC(GtkModuleConfigure),
415 (gpointer)module_clist );
416 gtk_signal_connect( GTK_OBJECT(module_select_button), "clicked",
417 GTK_SIGNAL_FUNC(GtkModuleSelected),
418 (gpointer)module_clist );
420 /* connect signal to track changes in the text box */
421 gtk_object_set_data( GTK_OBJECT(string_entry), "config_option",
423 gtk_signal_connect( GTK_OBJECT(string_entry), "changed",
424 GTK_SIGNAL_FUNC(GtkStringChanged),
425 (gpointer)config_dialog );
428 case CONFIG_ITEM_STRING:
429 case CONFIG_ITEM_FILE:
430 case CONFIG_ITEM_DIRECTORY:
432 if( !p_item->ppsz_list )
434 /* add input box with default value */
435 item_combo = string_entry = gtk_entry_new();
439 /* add combo box with default value */
443 for( i=0; p_item->ppsz_list[i]; i++ )
444 items = g_list_append( items, p_item->ppsz_list[i] );
446 item_combo = gtk_combo_new();
447 string_entry = GTK_COMBO(item_combo)->entry;
448 gtk_combo_set_popdown_strings( GTK_COMBO(item_combo),
453 vlc_mutex_lock( p_item->p_lock );
454 gtk_entry_set_text( GTK_ENTRY(string_entry),
455 p_item->psz_value ? p_item->psz_value : "" );
456 vlc_mutex_unlock( p_item->p_lock );
458 /* connect signal to track changes in the text box */
459 gtk_object_set_data( GTK_OBJECT(string_entry), "config_option",
461 gtk_signal_connect( GTK_OBJECT(string_entry), "changed",
462 GTK_SIGNAL_FUNC(GtkStringChanged),
463 (gpointer)config_dialog );
465 LABEL_AND_WIDGET( p_item->psz_text,
466 item_combo, p_item->psz_longtext );
469 case CONFIG_ITEM_INTEGER:
471 if (( p_item->i_max == 0) && ( p_item->i_min == 0))
473 /* add input box with default value */
474 item_adj = gtk_adjustment_new( p_item->i_value,
475 -1, 99999, 1, 10, 10 );
476 integer_spinbutton = gtk_spin_button_new( GTK_ADJUSTMENT(item_adj), 1, 0 );
478 /* connect signal to track changes in the spinbutton value */
479 gtk_object_set_data( GTK_OBJECT(integer_spinbutton),
480 "config_option", p_item->psz_name );
481 gtk_signal_connect( GTK_OBJECT(integer_spinbutton), "changed",
482 GTK_SIGNAL_FUNC(GtkIntChanged),
483 (gpointer)config_dialog );
485 LABEL_AND_WIDGET( p_item->psz_text,
486 integer_spinbutton, p_item->psz_longtext );
488 else /* use i_min and i_max */
490 item_adj = gtk_adjustment_new( p_item->i_value, p_item->i_min,
491 p_item->i_max, 1, 1, 0 );
492 integer_slider = gtk_hscale_new( GTK_ADJUSTMENT(item_adj));
493 gtk_scale_set_digits (GTK_SCALE(integer_slider), 0);
495 /* connect signal to track changes in the spinbutton value */
496 gtk_object_set_data( GTK_OBJECT(item_adj),
497 "config_option", p_item->psz_name );
498 gtk_signal_connect( GTK_OBJECT(item_adj), "value-changed",
499 GTK_SIGNAL_FUNC(GtkIntRangedChanged),
500 (gpointer)config_dialog );
502 LABEL_AND_WIDGET( p_item->psz_text,
503 integer_slider, p_item->psz_longtext );
507 case CONFIG_ITEM_FLOAT:
509 if (( p_item->f_max == 0.0) && ( p_item->f_min == 0.0))
511 /* add input box with default value */
512 item_adj = gtk_adjustment_new( p_item->f_value,
513 0, 99999, 0.01, 10, 10 );
514 float_spinbutton = gtk_spin_button_new( GTK_ADJUSTMENT(item_adj),
517 /* connect signal to track changes in the spinbutton value */
518 gtk_object_set_data( GTK_OBJECT(float_spinbutton),
519 "config_option", p_item->psz_name );
520 gtk_signal_connect( GTK_OBJECT(float_spinbutton), "changed",
521 GTK_SIGNAL_FUNC(GtkFloatChanged),
522 (gpointer)config_dialog );
524 LABEL_AND_WIDGET( p_item->psz_text,
525 float_spinbutton, p_item->psz_longtext );
527 else /* use f_min and f_max */
529 item_adj = gtk_adjustment_new( p_item->f_value, p_item->f_min,
530 p_item->f_max, 0.01, 0.01, 0 );
531 float_slider = gtk_hscale_new( GTK_ADJUSTMENT(item_adj));
532 gtk_scale_set_digits (GTK_SCALE(float_slider), 2);
534 /* connect signal to track changes in the spinbutton value */
535 gtk_object_set_data( GTK_OBJECT(item_adj),
536 "config_option", p_item->psz_name );
537 gtk_signal_connect( GTK_OBJECT(item_adj), "value-changed",
538 GTK_SIGNAL_FUNC(GtkFloatRangedChanged),
539 (gpointer)config_dialog );
541 LABEL_AND_WIDGET( p_item->psz_text,
542 float_slider, p_item->psz_longtext );
547 case CONFIG_ITEM_BOOL:
549 /* add check button */
550 bool_checkbutton = gtk_check_button_new();
551 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(bool_checkbutton),
554 /* connect signal to track changes in the button state */
555 gtk_object_set_data( GTK_OBJECT(bool_checkbutton), "config_option",
557 gtk_signal_connect( GTK_OBJECT(bool_checkbutton), "toggled",
558 GTK_SIGNAL_FUNC(GtkBoolChanged),
559 (gpointer)config_dialog );
561 LABEL_AND_WIDGET( p_item->psz_text,
562 bool_checkbutton, p_item->psz_longtext );
568 while( p_item->i_type != CONFIG_HINT_END && p_item++ );
570 vlc_list_release( p_list );
572 #ifndef MODULE_NAME_IS_gnome
573 /* Now let's add the action buttons at the bottom of the page */
574 dialog_action_area = GTK_DIALOG(config_dialog)->action_area;
575 gtk_container_set_border_width( GTK_CONTAINER(dialog_action_area), 4 );
577 /* add a new table for the config option */
578 item_hbox = gtk_hbox_new( FALSE, 0 );
579 gtk_box_pack_end( GTK_BOX(dialog_action_area), item_hbox,
581 item_hbox = gtk_hbox_new( FALSE, 0 );
582 gtk_box_pack_end( GTK_BOX(dialog_action_area), item_hbox,
586 /* Create the OK button */
587 #ifdef MODULE_NAME_IS_gnome
588 gnome_dialog_append_button( GNOME_DIALOG(config_dialog),
589 GNOME_STOCK_BUTTON_OK );
591 GTK_WIDGET(g_list_last(GNOME_DIALOG(config_dialog)->buttons)->data);
593 gnome_dialog_append_button( GNOME_DIALOG(config_dialog),
594 GNOME_STOCK_BUTTON_APPLY );
596 GTK_WIDGET(g_list_last(GNOME_DIALOG(config_dialog)->buttons)->data);
598 gnome_dialog_append_button_with_pixmap(
599 GNOME_DIALOG(config_dialog), _("Save"), GNOME_STOCK_PIXMAP_SAVE );
601 GTK_WIDGET(g_list_last(GNOME_DIALOG(config_dialog)->buttons)->data);
603 gnome_dialog_append_button( GNOME_DIALOG(config_dialog),
604 GNOME_STOCK_BUTTON_CANCEL );
606 GTK_WIDGET(g_list_last(GNOME_DIALOG(config_dialog)->buttons)->data);
608 ok_button = gtk_button_new_with_label( _("OK") );
609 gtk_box_pack_start( GTK_BOX(dialog_action_area), ok_button,
612 apply_button = gtk_button_new_with_label( _("Apply") );
613 gtk_box_pack_start( GTK_BOX(dialog_action_area), apply_button,
616 save_button = gtk_button_new_with_label( _("Save") );
617 gtk_box_pack_start( GTK_BOX(dialog_action_area), save_button,
620 cancel_button = gtk_button_new_with_label( _("Cancel") );
621 gtk_box_pack_start( GTK_BOX(dialog_action_area), cancel_button,
625 gtk_signal_connect( GTK_OBJECT(ok_button), "clicked",
626 GTK_SIGNAL_FUNC(GtkConfigOk),
628 gtk_widget_set_sensitive( apply_button, FALSE );
629 gtk_object_set_data( GTK_OBJECT(config_dialog), "apply_button",
631 gtk_signal_connect( GTK_OBJECT(apply_button), "clicked",
632 GTK_SIGNAL_FUNC(GtkConfigApply),
634 gtk_signal_connect( GTK_OBJECT(save_button), "clicked",
635 GTK_SIGNAL_FUNC(GtkConfigSave),
637 gtk_signal_connect( GTK_OBJECT(cancel_button), "clicked",
638 GTK_SIGNAL_FUNC(GtkConfigCancel),
643 /* Ok, job done successfully. Let's keep a reference to the dialog box */
644 gtk_object_set_data( GTK_OBJECT(p_intf->p_sys->p_window),
645 psz_module_name, config_dialog );
646 gtk_object_set_data( GTK_OBJECT(config_dialog), "psz_module_name",
649 /* we want this ref to be destroyed if the object is destroyed */
650 gtk_signal_connect( GTK_OBJECT(config_dialog), "destroy",
651 GTK_SIGNAL_FUNC(GtkConfigDialogDestroyed),
654 gtk_widget_show_all( config_dialog );
657 #undef LABEL_AND_WIDGET
660 /****************************************************************************
661 * GtkConfigApply: store the changes to the config inside the modules
662 * configuration structure and clear the hash table.
663 ****************************************************************************/
664 static void GtkConfigApply( GtkButton * button, gpointer user_data )
666 intf_thread_t *p_intf;
667 GHashTable *hash_table;
668 GtkWidget *apply_button;
670 hash_table = (GHashTable *)gtk_object_get_data( GTK_OBJECT(user_data),
671 "config_hash_table" );
672 p_intf = (intf_thread_t *)gtk_object_get_data( GTK_OBJECT(user_data),
674 g_hash_table_foreach_remove( hash_table, GtkSaveHashValue, (void*)p_intf );
676 /* change the highlight status of the Apply button */
677 apply_button = (GtkWidget *)gtk_object_get_data( GTK_OBJECT(user_data),
679 gtk_widget_set_sensitive( apply_button, FALSE );
682 static void GtkConfigOk( GtkButton * button, gpointer user_data )
684 GtkConfigApply( button, user_data );
685 gtk_widget_destroy( gtk_widget_get_toplevel( GTK_WIDGET (button) ) );
689 static void GtkConfigCancel( GtkButton * button, gpointer user_data )
691 gtk_widget_destroy( gtk_widget_get_toplevel( GTK_WIDGET (button) ) );
694 static void GtkConfigSave( GtkButton * button, gpointer user_data )
696 intf_thread_t *p_intf;
698 p_intf = (intf_thread_t *)gtk_object_get_data( GTK_OBJECT(user_data),
700 GtkConfigApply( button, user_data );
701 config_SaveConfigFile( p_intf, NULL );
704 /****************************************************************************
705 * GtkModuleHighlighted: display module description when an entry is selected
706 * in the clist, and activate the configure button if necessary.
707 ****************************************************************************/
708 static void GtkModuleHighlighted( GtkCList *module_clist, int row, int column,
709 GdkEventButton *event, gpointer user_data )
711 intf_thread_t *p_intf;
712 GtkWidget *config_button;
718 p_intf = (intf_thread_t *)gtk_object_get_data( GTK_OBJECT(module_clist),
721 if( !gtk_clist_get_text( GTK_CLIST(module_clist), row, 0, &psz_name ) )
726 /* look for module 'psz_name' */
727 p_list = vlc_list_find( p_intf, VLC_OBJECT_MODULE, FIND_ANYWHERE );
729 for( i_index = 0; i_index < p_list->i_count; i_index++ )
731 p_parser = (module_t *)p_list->p_values[i_index].p_object ;
733 if( !strcmp( p_parser->psz_object_name, psz_name ) )
735 gtk_object_set_data( GTK_OBJECT(module_clist),
736 "module_highlighted", p_parser );
737 config_button = gtk_object_get_data( GTK_OBJECT(module_clist),
739 if( p_parser->i_config_items )
740 gtk_widget_set_sensitive( config_button, TRUE );
742 gtk_widget_set_sensitive( config_button, FALSE );
748 vlc_list_release( p_list );
751 /****************************************************************************
752 * GtkModuleConfigure: display module configuration dialog box.
753 ****************************************************************************/
754 static void GtkModuleConfigure( GtkButton *button, gpointer user_data )
757 intf_thread_t *p_intf;
759 p_module = (module_t *)gtk_object_get_data( GTK_OBJECT(user_data),
760 "module_highlighted" );
762 if( !p_module ) return;
763 p_intf = (intf_thread_t *)gtk_object_get_data( GTK_OBJECT(button),
765 GtkCreateConfigDialog( p_module->psz_object_name, (gpointer)p_intf );
769 /****************************************************************************
770 * GtkModuleSelected: select module.
771 ****************************************************************************/
772 static void GtkModuleSelected( GtkButton *button, gpointer user_data )
777 p_module = (module_t *)gtk_object_get_data( GTK_OBJECT(user_data),
778 "module_highlighted" );
779 widget = (GtkWidget *)gtk_object_get_data( GTK_OBJECT(user_data),
781 if( !p_module ) return;
783 gtk_entry_set_text( GTK_ENTRY(widget), p_module->psz_object_name );
787 /****************************************************************************
788 * GtkStringChanged: signal called when the user changes a string value.
789 ****************************************************************************/
790 static void GtkStringChanged( GtkEditable *editable, gpointer user_data )
792 intf_thread_t *p_intf;
793 module_config_t *p_config;
794 GHashTable *hash_table;
795 GtkWidget *apply_button;
797 p_intf = (intf_thread_t *)gtk_object_get_data( GTK_OBJECT(editable),
799 hash_table = (GHashTable *)gtk_object_get_data( GTK_OBJECT(user_data),
800 "config_hash_table" );
801 /* free old p_config */
802 p_config = (module_config_t *)g_hash_table_lookup( hash_table,
803 (gpointer)editable );
804 if( p_config ) GtkFreeHashValue( NULL, (gpointer)p_config, (void *)p_intf );
806 p_config = malloc( sizeof(module_config_t) );
807 p_config->i_type = CONFIG_ITEM_STRING;
808 p_config->psz_value = gtk_editable_get_chars( editable, 0, -1 );
809 p_config->psz_name = (char *)gtk_object_get_data( GTK_OBJECT(editable),
812 g_hash_table_insert( hash_table, (gpointer)editable,
813 (gpointer)p_config );
815 /* change the highlight status of the Apply button */
816 apply_button = (GtkWidget *)gtk_object_get_data( GTK_OBJECT(user_data),
818 gtk_widget_set_sensitive( apply_button, TRUE );
820 /****************************************************************************
821 * GtkIntChanged: signal called when the user changes an integer value.
822 ****************************************************************************/
823 static void GtkIntChanged( GtkEditable *editable, gpointer user_data )
825 intf_thread_t *p_intf;
826 module_config_t *p_config;
827 GHashTable *hash_table;
828 GtkWidget *apply_button;
830 p_intf = (intf_thread_t *)gtk_object_get_data( GTK_OBJECT(editable),
832 gtk_spin_button_update( GTK_SPIN_BUTTON(editable) );
834 hash_table = (GHashTable *)gtk_object_get_data( GTK_OBJECT(user_data),
835 "config_hash_table" );
837 /* free old p_config */
838 p_config = (module_config_t *)g_hash_table_lookup( hash_table,
839 (gpointer)editable );
840 if( p_config ) GtkFreeHashValue( NULL, (gpointer)p_config, (void *)p_intf );
842 p_config = malloc( sizeof(module_config_t) );
843 p_config->i_type = CONFIG_ITEM_INTEGER;
844 p_config->i_value = gtk_spin_button_get_value_as_int(
845 GTK_SPIN_BUTTON(editable) );
846 p_config->psz_name = (char *)gtk_object_get_data( GTK_OBJECT(editable),
849 g_hash_table_insert( hash_table, (gpointer)editable,
850 (gpointer)p_config );
852 /* change the highlight status of the Apply button */
853 apply_button = (GtkWidget *)gtk_object_get_data( GTK_OBJECT(user_data),
855 gtk_widget_set_sensitive( apply_button, TRUE );
859 /***************************************************************************************
860 * GtkIntRangedChanged: signal called when the user changes an integer with range value.
861 **************************************************************************************/
862 static void GtkIntRangedChanged( GtkEditable *editable, gpointer user_data )
864 intf_thread_t *p_intf;
865 module_config_t *p_config;
866 GHashTable *hash_table;
867 GtkWidget *apply_button;
869 p_intf = (intf_thread_t *)gtk_object_get_data( GTK_OBJECT(editable),
872 hash_table = (GHashTable *)gtk_object_get_data( GTK_OBJECT(user_data),
873 "config_hash_table" );
875 /* free old p_config */
876 p_config = (module_config_t *)g_hash_table_lookup( hash_table,
877 (gpointer)editable );
878 if( p_config ) GtkFreeHashValue( NULL, (gpointer)p_config, (void *)p_intf );
880 p_config = malloc( sizeof(module_config_t) );
881 p_config->i_type = CONFIG_ITEM_INTEGER;
882 p_config->i_value = ((GTK_ADJUSTMENT(editable))->value);
883 p_config->psz_name = (char *)gtk_object_get_data( GTK_OBJECT(editable),
886 g_hash_table_insert( hash_table, (gpointer)editable,
887 (gpointer)p_config );
889 /* change the highlight status of the Apply button */
890 apply_button = (GtkWidget *)gtk_object_get_data( GTK_OBJECT(user_data),
892 gtk_widget_set_sensitive( apply_button, TRUE );
895 /****************************************************************************
896 * GtkFloatChanged: signal called when the user changes a float value.
897 ****************************************************************************/
898 static void GtkFloatChanged( GtkEditable *editable, gpointer user_data )
900 intf_thread_t *p_intf;
901 module_config_t *p_config;
902 GHashTable *hash_table;
903 GtkWidget *apply_button;
905 p_intf = (intf_thread_t *)gtk_object_get_data( GTK_OBJECT(editable),
907 gtk_spin_button_update( GTK_SPIN_BUTTON(editable) );
909 hash_table = (GHashTable *)gtk_object_get_data( GTK_OBJECT(user_data),
910 "config_hash_table" );
912 /* free old p_config */
913 p_config = (module_config_t *)g_hash_table_lookup( hash_table,
914 (gpointer)editable );
915 if( p_config ) GtkFreeHashValue( NULL, (gpointer)p_config, (void *)p_intf );
917 p_config = malloc( sizeof(module_config_t) );
918 p_config->i_type = CONFIG_ITEM_FLOAT;
919 p_config->f_value = gtk_spin_button_get_value_as_float(
920 GTK_SPIN_BUTTON(editable) );
921 p_config->psz_name = (char *)gtk_object_get_data( GTK_OBJECT(editable),
924 g_hash_table_insert( hash_table, (gpointer)editable,
925 (gpointer)p_config );
927 /* change the highlight status of the Apply button */
928 apply_button = (GtkWidget *)gtk_object_get_data( GTK_OBJECT(user_data),
930 gtk_widget_set_sensitive( apply_button, TRUE );
933 /***************************************************************************************
934 * GtkIntRangedChanged: signal called when the user changes an integer with range value.
935 **************************************************************************************/
936 static void GtkFloatRangedChanged( GtkEditable *editable, gpointer user_data )
938 intf_thread_t *p_intf;
939 module_config_t *p_config;
940 GHashTable *hash_table;
941 GtkWidget *apply_button;
943 p_intf = (intf_thread_t *)gtk_object_get_data( GTK_OBJECT(editable),
946 hash_table = (GHashTable *)gtk_object_get_data( GTK_OBJECT(user_data),
947 "config_hash_table" );
949 /* free old p_config */
950 p_config = (module_config_t *)g_hash_table_lookup( hash_table,
951 (gpointer)editable );
952 if( p_config ) GtkFreeHashValue( NULL, (gpointer)p_config, (void *)p_intf );
954 p_config = malloc( sizeof(module_config_t) );
955 p_config->i_type = CONFIG_ITEM_FLOAT;
956 p_config->f_value = ((GTK_ADJUSTMENT(editable))->value);
957 p_config->psz_name = (char *)gtk_object_get_data( GTK_OBJECT(editable),
960 g_hash_table_insert( hash_table, (gpointer)editable,
961 (gpointer)p_config );
963 /* change the highlight status of the Apply button */
964 apply_button = (GtkWidget *)gtk_object_get_data( GTK_OBJECT(user_data),
966 gtk_widget_set_sensitive( apply_button, TRUE );
969 /****************************************************************************
970 * GtkBoolChanged: signal called when the user changes a bool value.
971 ****************************************************************************/
972 static void GtkBoolChanged( GtkToggleButton *button, gpointer user_data )
974 intf_thread_t *p_intf;
975 module_config_t *p_config;
976 GHashTable *hash_table;
977 GtkWidget *apply_button;
979 p_intf = (intf_thread_t *)gtk_object_get_data( GTK_OBJECT(button),
981 hash_table = (GHashTable *)gtk_object_get_data( GTK_OBJECT(user_data),
982 "config_hash_table" );
984 /* free old p_config */
985 p_config = (module_config_t *)g_hash_table_lookup( hash_table,
987 if( p_config ) GtkFreeHashValue( NULL, (gpointer)p_config, (void *)p_intf );
989 p_config = malloc( sizeof(module_config_t) );
990 p_config->i_type = CONFIG_ITEM_BOOL;
991 p_config->i_value = gtk_toggle_button_get_active( button );
992 p_config->psz_name = (char *)gtk_object_get_data( GTK_OBJECT(button),
995 g_hash_table_insert( hash_table, (gpointer)button,
996 (gpointer)p_config );
998 /* change the highlight status of the Apply button */
999 apply_button = (GtkWidget *)gtk_object_get_data( GTK_OBJECT(user_data),
1001 gtk_widget_set_sensitive( apply_button, TRUE );
1004 /****************************************************************************
1005 * GtkFreeHashTable: signal called when the config hash table is destroyed.
1006 ****************************************************************************/
1007 static void GtkFreeHashTable( GtkObject *object )
1009 GHashTable *hash_table = (GHashTable *)gtk_object_get_data( object,
1010 "config_hash_table" );
1011 intf_thread_t *p_intf = (intf_thread_t *)gtk_object_get_data( object,
1014 g_hash_table_foreach( hash_table, GtkFreeHashValue, (void *)p_intf );
1015 g_hash_table_destroy( hash_table );
1018 /****************************************************************************
1019 * GtkFreeHashValue: signal called when an element of the config hash table
1021 ****************************************************************************/
1022 static void GtkFreeHashValue( gpointer key, gpointer value, gpointer user_data)
1024 module_config_t * p_config = (module_config_t *)value;
1026 if( p_config->i_type == CONFIG_ITEM_STRING )
1027 if( p_config->psz_value ) g_free( p_config->psz_value );
1031 /****************************************************************************
1032 * GtkSaveHashValue: callback used when enumerating the hash table in
1034 ****************************************************************************/
1035 static gboolean GtkSaveHashValue( gpointer key, gpointer value,
1036 gpointer user_data )
1038 intf_thread_t * p_intf = (intf_thread_t *)user_data;
1039 module_config_t * p_config = (module_config_t *)value;
1041 switch( p_config->i_type )
1044 case CONFIG_ITEM_STRING:
1045 case CONFIG_ITEM_FILE:
1046 case CONFIG_ITEM_DIRECTORY:
1047 case CONFIG_ITEM_MODULE:
1048 config_PutPsz( p_intf, p_config->psz_name,
1049 *p_config->psz_value ? p_config->psz_value : NULL );
1051 case CONFIG_ITEM_INTEGER:
1052 case CONFIG_ITEM_BOOL:
1053 config_PutInt( p_intf, p_config->psz_name, p_config->i_value );
1055 case CONFIG_ITEM_FLOAT:
1056 config_PutFloat( p_intf, p_config->psz_name, p_config->f_value );
1060 /* free the hash value we allocated */
1061 if( p_config->i_type == CONFIG_ITEM_STRING )
1062 g_free( p_config->psz_value );
1065 /* return TRUE so glib will free the hash entry */
1069 /****************************************************************************
1070 * GtkConfigDialogDestroyed: callback triggered when the config dialog box is
1072 ****************************************************************************/
1073 static void GtkConfigDialogDestroyed( GtkObject *object, gpointer user_data )
1075 intf_thread_t *p_intf = (intf_thread_t *)user_data;
1076 char *psz_module_name;
1078 psz_module_name = gtk_object_get_data( object, "psz_module_name" );
1080 /* remove the ref to the dialog box */
1081 gtk_object_set_data( GTK_OBJECT(p_intf->p_sys->p_window),
1082 psz_module_name, NULL );
1084 GtkFreeHashTable( object );