1 /*****************************************************************************
2 * gtk_preferences.c: functions to handle the preferences dialog box.
3 *****************************************************************************
4 * Copyright (C) 2000, 2001 VideoLAN
5 * $Id: preferences.c,v 1.5 2002/12/06 16:34:07 sam 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 GtkFloatChanged ( GtkEditable *, gpointer );
66 static void GtkBoolChanged ( GtkToggleButton *, gpointer );
68 static void GtkFreeHashTable ( GtkObject *object );
69 static void GtkFreeHashValue ( gpointer, gpointer, gpointer );
70 static gboolean GtkSaveHashValue ( gpointer, gpointer, gpointer );
72 static void GtkModuleConfigure ( GtkButton *, gpointer );
73 static void GtkModuleSelected ( GtkButton *, gpointer );
74 static void GtkModuleHighlighted ( GtkCList *, int, int, GdkEventButton *,
77 /****************************************************************************
78 * Callback for menuitems: display configuration interface window
79 ****************************************************************************/
80 void GtkPreferencesShow( GtkMenuItem * menuitem, gpointer user_data )
82 intf_thread_t * p_intf;
84 p_intf = GtkGetIntf( menuitem );
86 GtkCreateConfigDialog( "main", p_intf );
89 /****************************************************************************
90 * GtkCreateConfigDialog: dynamically creates the configuration dialog
91 * box from all the configuration data provided by the selected module.
92 ****************************************************************************/
94 /* create a new tooltipped area */
95 #define TOOLTIP( text ) \
96 /* create an event box to catch some events */ \
97 item_event_box = gtk_event_box_new(); \
98 /* add a tooltip on mouseover */ \
99 gtk_tooltips_set_tip( p_intf->p_sys->p_tooltips, \
100 item_event_box, text, "" ); \
101 gtk_container_set_border_width( GTK_CONTAINER(item_event_box), 4 );
103 /* draws a right aligned label in side of a widget */
104 #define LABEL_AND_WIDGET( label_text, widget, tooltip ) \
105 gtk_table_resize( GTK_TABLE(category_table), ++rows, 2 ); \
106 item_align = gtk_alignment_new( 1, .5, 0, 0 ); \
107 item_label = gtk_label_new( label_text ); \
108 gtk_container_add( GTK_CONTAINER(item_align), item_label ); \
109 gtk_table_attach_defaults( GTK_TABLE(category_table), item_align, \
110 0, 1, rows - 1, rows ); \
111 item_align = gtk_alignment_new( 0, .5, .5, 0 ); \
112 gtk_container_add( GTK_CONTAINER(item_align), widget ); \
114 gtk_container_add( GTK_CONTAINER(item_event_box), item_align ); \
115 gtk_table_attach_defaults( GTK_TABLE(category_table), item_event_box, \
116 1, 2, rows - 1, rows );
118 static void GtkCreateConfigDialog( char *psz_module_name,
119 intf_thread_t *p_intf )
121 module_t **pp_parser;
123 module_config_t *p_item;
127 GHashTable *config_hash_table;
129 GtkWidget *item_event_box;
131 GtkWidget *config_dialog;
132 GtkWidget *config_dialog_vbox;
133 GtkWidget *config_notebook;
135 GtkWidget *category_table = NULL;
136 GtkWidget *category_label = NULL;
138 #ifndef MODULE_NAME_IS_gnome
139 GtkWidget *dialog_action_area;
142 GtkWidget *ok_button;
143 GtkWidget *apply_button;
144 GtkWidget *save_button;
145 GtkWidget *cancel_button;
147 GtkWidget *item_align;
148 GtkWidget *item_frame;
149 GtkWidget *item_hbox;
150 GtkWidget *item_label;
151 GtkWidget *item_vbox;
152 GtkWidget *item_combo;
153 GtkWidget *string_entry;
154 GtkWidget *integer_spinbutton;
155 GtkWidget *float_spinbutton;
157 GtkWidget *bool_checkbutton;
158 GtkWidget *module_clist;
159 GtkWidget *module_config_button;
160 GtkWidget *module_select_button;
162 gint category_max_height;
164 /* Check if the dialog box is already opened because we don't want to
165 * duplicate identical dialog windows. */
166 config_dialog = (GtkWidget *)gtk_object_get_data(
167 GTK_OBJECT(p_intf->p_sys->p_window), psz_module_name );
170 /* Yeah it was open */
171 gtk_widget_grab_focus( config_dialog );
176 /* Look for the selected module */
177 p_list = vlc_list_find( p_intf, VLC_OBJECT_MODULE, FIND_ANYWHERE );
179 for( pp_parser = (module_t **)p_list->pp_objects ;
185 && !strcmp( psz_module_name, (*pp_parser)->psz_object_name ) )
193 vlc_list_release( p_list );
197 /* We found it, now we can start building its configuration interface */
198 /* Create the configuration dialog box */
200 #ifdef MODULE_NAME_IS_gnome
201 config_dialog = gnome_dialog_new( (*pp_parser)->psz_longname, NULL );
202 config_dialog_vbox = GNOME_DIALOG(config_dialog)->vbox;
204 config_dialog = gtk_dialog_new();
205 gtk_window_set_title( GTK_WINDOW(config_dialog),
206 (*pp_parser)->psz_longname );
207 config_dialog_vbox = GTK_DIALOG(config_dialog)->vbox;
210 gtk_object_set_data( GTK_OBJECT(config_dialog), "p_intf", p_intf );
212 category_max_height = config_GetInt( p_intf, MODULE_STRING "-prefs-maxh" );
214 gtk_window_set_policy( GTK_WINDOW(config_dialog), TRUE, TRUE, FALSE );
215 gtk_container_set_border_width( GTK_CONTAINER(config_dialog_vbox), 0 );
217 /* Create our config hash table and associate it with the dialog box */
218 config_hash_table = g_hash_table_new( NULL, NULL );
219 gtk_object_set_data( GTK_OBJECT(config_dialog),
220 "config_hash_table", config_hash_table );
222 /* Create notebook */
223 config_notebook = gtk_notebook_new();
224 gtk_notebook_set_scrollable( GTK_NOTEBOOK(config_notebook), TRUE );
225 gtk_container_add( GTK_CONTAINER(config_dialog_vbox), config_notebook );
227 /* Enumerate config options and add corresponding config boxes */
228 p_item = (*pp_parser)->p_config;
232 switch( p_item->i_type )
235 case CONFIG_HINT_CATEGORY:
236 case CONFIG_HINT_END:
239 * Before we start building the interface for the new category, we
240 * must close/finish the previous one we were generating.
244 GtkWidget *_scrolled_window;
245 GtkWidget *_viewport;
247 GtkRequisition _requisition;
249 /* create a vbox to deal with EXPAND/FILL issues in the
250 * notebook page, and pack it with the previously generated
252 _vbox = gtk_vbox_new( FALSE, 0 );
253 gtk_container_set_border_width( GTK_CONTAINER(_vbox), 4 );
254 gtk_box_pack_start( GTK_BOX(_vbox), category_table,
257 /* create a new scrolled window that will contain all of the
259 _scrolled_window = gtk_scrolled_window_new( NULL, NULL );
260 gtk_scrolled_window_set_policy(
261 GTK_SCROLLED_WINDOW(_scrolled_window), GTK_POLICY_NEVER,
262 GTK_POLICY_AUTOMATIC );
263 /* add scrolled window as a notebook page */
264 gtk_notebook_append_page( GTK_NOTEBOOK(config_notebook),
265 _scrolled_window, category_label );
266 /* pack the vbox into the scrolled window */
267 _viewport = gtk_viewport_new( NULL, NULL );
268 gtk_viewport_set_shadow_type( GTK_VIEWPORT(_viewport),
270 gtk_container_add( GTK_CONTAINER(_viewport), _vbox );
271 gtk_container_add( GTK_CONTAINER(_scrolled_window),
274 /* set the size of the scrolled window to the size of the
276 gtk_widget_show_all( _vbox );
277 gtk_widget_size_request( _vbox, &_requisition );
278 if( _requisition.height > category_max_height )
279 gtk_widget_set_usize( _scrolled_window, -1,
280 category_max_height );
282 gtk_widget_set_usize( _scrolled_window, -1,
283 _requisition.height );
288 * Now we can start taking care of the new category
291 if( p_item->i_type == CONFIG_HINT_CATEGORY )
293 /* create a new table for right-left alignment of children */
294 category_table = gtk_table_new( 0, 0, FALSE );
295 gtk_table_set_col_spacings( GTK_TABLE(category_table), 4 );
298 /* create a new category label */
299 category_label = gtk_label_new( p_item->psz_text );
304 case CONFIG_ITEM_MODULE:
306 item_frame = gtk_frame_new( p_item->psz_text );
308 gtk_table_resize( GTK_TABLE(category_table), ++rows, 2 );
309 gtk_table_attach_defaults( GTK_TABLE(category_table), item_frame,
310 0, 2, rows - 1, rows );
312 item_vbox = gtk_vbox_new( FALSE, 4 );
313 gtk_container_add( GTK_CONTAINER(item_frame), item_vbox );
315 /* create a new clist widget */
317 gchar * titles[] = { N_("Name"), N_("Description") };
318 titles[0] = _(titles[0]);
319 titles[1] = _(titles[1]);
321 module_clist = gtk_clist_new_with_titles( 2, titles );
323 gtk_object_set_data( GTK_OBJECT(module_clist), "p_intf", p_intf );
324 gtk_clist_column_titles_passive( GTK_CLIST(module_clist) );
325 gtk_clist_set_selection_mode( GTK_CLIST(module_clist),
326 GTK_SELECTION_SINGLE);
327 gtk_container_add( GTK_CONTAINER(item_vbox), module_clist );
329 /* build a list of available modules */
332 pp_parser = (module_t **)p_list->pp_objects;
334 for( ; *pp_parser ; pp_parser++ )
336 if( !strcmp( (*pp_parser)->psz_capability,
339 entry[0] = (*pp_parser)->psz_object_name;
340 entry[1] = (*pp_parser)->psz_longname;
341 gtk_clist_append( GTK_CLIST(module_clist), entry );
346 gtk_clist_set_column_auto_resize( GTK_CLIST(module_clist),
348 gtk_clist_set_column_auto_resize( GTK_CLIST(module_clist),
351 /* connect signals to the modules list */
352 gtk_signal_connect( GTK_OBJECT(module_clist), "select_row",
353 GTK_SIGNAL_FUNC(GtkModuleHighlighted),
356 /* hbox holding the "select" and "configure" buttons */
357 item_hbox = gtk_hbox_new( FALSE, 4 );
358 gtk_container_add( GTK_CONTAINER(item_vbox), item_hbox);
360 /* add configure button */
361 module_config_button =
362 gtk_button_new_with_label( _("Configure") );
363 gtk_widget_set_sensitive( module_config_button, FALSE );
364 gtk_container_add( GTK_CONTAINER(item_hbox),
365 module_config_button );
366 gtk_object_set_data( GTK_OBJECT(module_config_button),
368 gtk_object_set_data( GTK_OBJECT(module_clist),
369 "config_button", module_config_button );
371 /* add select button */
372 module_select_button =
373 gtk_button_new_with_label( _("Select") );
374 gtk_container_add( GTK_CONTAINER(item_hbox),
375 module_select_button );
376 /* add a tooltip on mouseover */
377 gtk_tooltips_set_tip( p_intf->p_sys->p_tooltips,
378 module_select_button,
379 p_item->psz_longtext, "" );
381 /* hbox holding the "selected" label and text input */
382 item_hbox = gtk_hbox_new( FALSE, 4 );
383 gtk_container_add( GTK_CONTAINER(item_vbox), item_hbox);
385 item_label = gtk_label_new( _("Selected:") );
386 gtk_container_add( GTK_CONTAINER(item_hbox), item_label );
388 /* add input box with default value */
389 string_entry = gtk_entry_new();
390 gtk_object_set_data( GTK_OBJECT(module_clist),
391 "module_entry", string_entry );
392 gtk_container_add( GTK_CONTAINER(item_hbox), string_entry );
393 vlc_mutex_lock( p_item->p_lock );
394 gtk_entry_set_text( GTK_ENTRY(string_entry),
395 p_item->psz_value ? p_item->psz_value : "" );
396 vlc_mutex_unlock( p_item->p_lock );
397 /* add a tooltip on mouseover */
398 gtk_tooltips_set_tip( p_intf->p_sys->p_tooltips,
399 string_entry, p_item->psz_longtext, "" );
401 /* connect signals to the buttons */
402 gtk_signal_connect( GTK_OBJECT(module_config_button), "clicked",
403 GTK_SIGNAL_FUNC(GtkModuleConfigure),
404 (gpointer)module_clist );
405 gtk_signal_connect( GTK_OBJECT(module_select_button), "clicked",
406 GTK_SIGNAL_FUNC(GtkModuleSelected),
407 (gpointer)module_clist );
409 /* connect signal to track changes in the text box */
410 gtk_object_set_data( GTK_OBJECT(string_entry), "config_option",
412 gtk_signal_connect( GTK_OBJECT(string_entry), "changed",
413 GTK_SIGNAL_FUNC(GtkStringChanged),
414 (gpointer)config_dialog );
417 case CONFIG_ITEM_STRING:
418 case CONFIG_ITEM_FILE:
420 if( !p_item->ppsz_list )
422 /* add input box with default value */
423 item_combo = string_entry = gtk_entry_new();
427 /* add combo box with default value */
431 for( i=0; p_item->ppsz_list[i]; i++ )
432 items = g_list_append( items, p_item->ppsz_list[i] );
434 item_combo = gtk_combo_new();
435 string_entry = GTK_COMBO(item_combo)->entry;
436 gtk_combo_set_popdown_strings( GTK_COMBO(item_combo),
441 vlc_mutex_lock( p_item->p_lock );
442 gtk_entry_set_text( GTK_ENTRY(string_entry),
443 p_item->psz_value ? p_item->psz_value : "" );
444 vlc_mutex_unlock( p_item->p_lock );
446 /* connect signal to track changes in the text box */
447 gtk_object_set_data( GTK_OBJECT(string_entry), "config_option",
449 gtk_signal_connect( GTK_OBJECT(string_entry), "changed",
450 GTK_SIGNAL_FUNC(GtkStringChanged),
451 (gpointer)config_dialog );
453 LABEL_AND_WIDGET( p_item->psz_text,
454 item_combo, p_item->psz_longtext );
457 case CONFIG_ITEM_INTEGER:
459 /* add input box with default value */
460 item_adj = gtk_adjustment_new( p_item->i_value,
461 -1, 99999, 1, 10, 10 );
462 integer_spinbutton = gtk_spin_button_new( GTK_ADJUSTMENT(item_adj),
465 /* connect signal to track changes in the spinbutton value */
466 gtk_object_set_data( GTK_OBJECT(integer_spinbutton),
467 "config_option", p_item->psz_name );
468 gtk_signal_connect( GTK_OBJECT(integer_spinbutton), "changed",
469 GTK_SIGNAL_FUNC(GtkIntChanged),
470 (gpointer)config_dialog );
472 LABEL_AND_WIDGET( p_item->psz_text,
473 integer_spinbutton, p_item->psz_longtext );
476 case CONFIG_ITEM_FLOAT:
478 /* add input box with default value */
479 item_adj = gtk_adjustment_new( p_item->f_value,
480 0, 99999, 0.01, 10, 10 );
481 float_spinbutton = gtk_spin_button_new( GTK_ADJUSTMENT(item_adj),
484 /* connect signal to track changes in the spinbutton value */
485 gtk_object_set_data( GTK_OBJECT(float_spinbutton),
486 "config_option", p_item->psz_name );
487 gtk_signal_connect( GTK_OBJECT(float_spinbutton), "changed",
488 GTK_SIGNAL_FUNC(GtkFloatChanged),
489 (gpointer)config_dialog );
491 LABEL_AND_WIDGET( p_item->psz_text,
492 float_spinbutton, p_item->psz_longtext );
495 case CONFIG_ITEM_BOOL:
497 /* add check button */
498 bool_checkbutton = gtk_check_button_new();
499 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(bool_checkbutton),
502 /* connect signal to track changes in the button state */
503 gtk_object_set_data( GTK_OBJECT(bool_checkbutton), "config_option",
505 gtk_signal_connect( GTK_OBJECT(bool_checkbutton), "toggled",
506 GTK_SIGNAL_FUNC(GtkBoolChanged),
507 (gpointer)config_dialog );
509 LABEL_AND_WIDGET( p_item->psz_text,
510 bool_checkbutton, p_item->psz_longtext );
516 while( p_item->i_type != CONFIG_HINT_END && p_item++ );
518 vlc_list_release( p_list );
520 #ifndef MODULE_NAME_IS_gnome
521 /* Now let's add the action buttons at the bottom of the page */
522 dialog_action_area = GTK_DIALOG(config_dialog)->action_area;
523 gtk_container_set_border_width( GTK_CONTAINER(dialog_action_area), 4 );
525 /* add a new table for the config option */
526 item_hbox = gtk_hbox_new( FALSE, 0 );
527 gtk_box_pack_end( GTK_BOX(dialog_action_area), item_hbox,
529 item_hbox = gtk_hbox_new( FALSE, 0 );
530 gtk_box_pack_end( GTK_BOX(dialog_action_area), item_hbox,
534 /* Create the OK button */
535 #ifdef MODULE_NAME_IS_gnome
536 gnome_dialog_append_button( GNOME_DIALOG(config_dialog),
537 GNOME_STOCK_BUTTON_OK );
539 GTK_WIDGET(g_list_last(GNOME_DIALOG(config_dialog)->buttons)->data);
541 gnome_dialog_append_button( GNOME_DIALOG(config_dialog),
542 GNOME_STOCK_BUTTON_APPLY );
544 GTK_WIDGET(g_list_last(GNOME_DIALOG(config_dialog)->buttons)->data);
546 gnome_dialog_append_button_with_pixmap(
547 GNOME_DIALOG(config_dialog), _("Save"), GNOME_STOCK_PIXMAP_SAVE );
549 GTK_WIDGET(g_list_last(GNOME_DIALOG(config_dialog)->buttons)->data);
551 gnome_dialog_append_button( GNOME_DIALOG(config_dialog),
552 GNOME_STOCK_BUTTON_CANCEL );
554 GTK_WIDGET(g_list_last(GNOME_DIALOG(config_dialog)->buttons)->data);
556 ok_button = gtk_button_new_with_label( _("OK") );
557 gtk_box_pack_start( GTK_BOX(dialog_action_area), ok_button,
560 apply_button = gtk_button_new_with_label( _("Apply") );
561 gtk_box_pack_start( GTK_BOX(dialog_action_area), apply_button,
564 save_button = gtk_button_new_with_label( _("Save") );
565 gtk_box_pack_start( GTK_BOX(dialog_action_area), save_button,
568 cancel_button = gtk_button_new_with_label( _("Cancel") );
569 gtk_box_pack_start( GTK_BOX(dialog_action_area), cancel_button,
573 gtk_signal_connect( GTK_OBJECT(ok_button), "clicked",
574 GTK_SIGNAL_FUNC(GtkConfigOk),
576 gtk_widget_set_sensitive( apply_button, FALSE );
577 gtk_object_set_data( GTK_OBJECT(config_dialog), "apply_button",
579 gtk_signal_connect( GTK_OBJECT(apply_button), "clicked",
580 GTK_SIGNAL_FUNC(GtkConfigApply),
582 gtk_signal_connect( GTK_OBJECT(save_button), "clicked",
583 GTK_SIGNAL_FUNC(GtkConfigSave),
585 gtk_signal_connect( GTK_OBJECT(cancel_button), "clicked",
586 GTK_SIGNAL_FUNC(GtkConfigCancel),
591 /* Ok, job done successfully. Let's keep a reference to the dialog box */
592 gtk_object_set_data( GTK_OBJECT(p_intf->p_sys->p_window),
593 psz_module_name, config_dialog );
594 gtk_object_set_data( GTK_OBJECT(config_dialog), "psz_module_name",
597 /* we want this ref to be destroyed if the object is destroyed */
598 gtk_signal_connect( GTK_OBJECT(config_dialog), "destroy",
599 GTK_SIGNAL_FUNC(GtkConfigDialogDestroyed),
602 gtk_widget_show_all( config_dialog );
605 #undef LABEL_AND_WIDGET
608 /****************************************************************************
609 * GtkConfigApply: store the changes to the config inside the modules
610 * configuration structure and clear the hash table.
611 ****************************************************************************/
612 static void GtkConfigApply( GtkButton * button, gpointer user_data )
614 intf_thread_t *p_intf;
615 GHashTable *hash_table;
616 GtkWidget *apply_button;
618 hash_table = (GHashTable *)gtk_object_get_data( GTK_OBJECT(user_data),
619 "config_hash_table" );
620 p_intf = (intf_thread_t *)gtk_object_get_data( GTK_OBJECT(user_data),
622 g_hash_table_foreach_remove( hash_table, GtkSaveHashValue, (void*)p_intf );
624 /* change the highlight status of the Apply button */
625 apply_button = (GtkWidget *)gtk_object_get_data( GTK_OBJECT(user_data),
627 gtk_widget_set_sensitive( apply_button, FALSE );
630 static void GtkConfigOk( GtkButton * button, gpointer user_data )
632 GtkConfigApply( button, user_data );
633 gtk_widget_destroy( gtk_widget_get_toplevel( GTK_WIDGET (button) ) );
637 static void GtkConfigCancel( GtkButton * button, gpointer user_data )
639 gtk_widget_destroy( gtk_widget_get_toplevel( GTK_WIDGET (button) ) );
642 static void GtkConfigSave( GtkButton * button, gpointer user_data )
644 intf_thread_t *p_intf;
646 p_intf = (intf_thread_t *)gtk_object_get_data( GTK_OBJECT(user_data),
648 GtkConfigApply( button, user_data );
649 config_SaveConfigFile( p_intf, NULL );
652 /****************************************************************************
653 * GtkModuleHighlighted: display module description when an entry is selected
654 * in the clist, and activate the configure button if necessary.
655 ****************************************************************************/
656 static void GtkModuleHighlighted( GtkCList *module_clist, int row, int column,
657 GdkEventButton *event, gpointer user_data )
659 intf_thread_t *p_intf;
660 GtkWidget *config_button;
661 module_t **pp_parser;
665 p_intf = (intf_thread_t *)gtk_object_get_data( GTK_OBJECT(module_clist),
668 if( !gtk_clist_get_text( GTK_CLIST(module_clist), row, 0, &psz_name ) )
673 /* look for module 'psz_name' */
674 p_list = vlc_list_find( p_intf, VLC_OBJECT_MODULE, FIND_ANYWHERE );
676 for( pp_parser = (module_t **)p_list->pp_objects ;
680 if( !strcmp( (*pp_parser)->psz_object_name, psz_name ) )
682 gtk_object_set_data( GTK_OBJECT(module_clist),
683 "module_highlighted", (*pp_parser) );
684 config_button = gtk_object_get_data( GTK_OBJECT(module_clist),
686 if( (*pp_parser)->i_config_items )
687 gtk_widget_set_sensitive( config_button, TRUE );
689 gtk_widget_set_sensitive( config_button, FALSE );
695 vlc_list_release( p_list );
698 /****************************************************************************
699 * GtkModuleConfigure: display module configuration dialog box.
700 ****************************************************************************/
701 static void GtkModuleConfigure( GtkButton *button, gpointer user_data )
704 intf_thread_t *p_intf;
706 p_module = (module_t *)gtk_object_get_data( GTK_OBJECT(user_data),
707 "module_highlighted" );
709 if( !p_module ) return;
710 p_intf = (intf_thread_t *)gtk_object_get_data( GTK_OBJECT(button),
712 GtkCreateConfigDialog( p_module->psz_object_name, (gpointer)p_intf );
716 /****************************************************************************
717 * GtkModuleSelected: select module.
718 ****************************************************************************/
719 static void GtkModuleSelected( GtkButton *button, gpointer user_data )
724 p_module = (module_t *)gtk_object_get_data( GTK_OBJECT(user_data),
725 "module_highlighted" );
726 widget = (GtkWidget *)gtk_object_get_data( GTK_OBJECT(user_data),
728 if( !p_module ) return;
730 gtk_entry_set_text( GTK_ENTRY(widget), p_module->psz_object_name );
734 /****************************************************************************
735 * GtkStringChanged: signal called when the user changes a string value.
736 ****************************************************************************/
737 static void GtkStringChanged( GtkEditable *editable, gpointer user_data )
739 intf_thread_t *p_intf;
740 module_config_t *p_config;
741 GHashTable *hash_table;
742 GtkWidget *apply_button;
744 p_intf = (intf_thread_t *)gtk_object_get_data( GTK_OBJECT(editable),
746 hash_table = (GHashTable *)gtk_object_get_data( GTK_OBJECT(user_data),
747 "config_hash_table" );
748 /* free old p_config */
749 p_config = (module_config_t *)g_hash_table_lookup( hash_table,
750 (gpointer)editable );
751 if( p_config ) GtkFreeHashValue( NULL, (gpointer)p_config, (void *)p_intf );
753 p_config = malloc( sizeof(module_config_t) );
754 p_config->i_type = CONFIG_ITEM_STRING;
755 p_config->psz_value = gtk_editable_get_chars( editable, 0, -1 );
756 p_config->psz_name = (char *)gtk_object_get_data( GTK_OBJECT(editable),
759 g_hash_table_insert( hash_table, (gpointer)editable,
760 (gpointer)p_config );
762 /* change the highlight status of the Apply button */
763 apply_button = (GtkWidget *)gtk_object_get_data( GTK_OBJECT(user_data),
765 gtk_widget_set_sensitive( apply_button, TRUE );
768 /****************************************************************************
769 * GtkIntChanged: signal called when the user changes an integer value.
770 ****************************************************************************/
771 static void GtkIntChanged( GtkEditable *editable, gpointer user_data )
773 intf_thread_t *p_intf;
774 module_config_t *p_config;
775 GHashTable *hash_table;
776 GtkWidget *apply_button;
778 p_intf = (intf_thread_t *)gtk_object_get_data( GTK_OBJECT(editable),
780 gtk_spin_button_update( GTK_SPIN_BUTTON(editable) );
782 hash_table = (GHashTable *)gtk_object_get_data( GTK_OBJECT(user_data),
783 "config_hash_table" );
785 /* free old p_config */
786 p_config = (module_config_t *)g_hash_table_lookup( hash_table,
787 (gpointer)editable );
788 if( p_config ) GtkFreeHashValue( NULL, (gpointer)p_config, (void *)p_intf );
790 p_config = malloc( sizeof(module_config_t) );
791 p_config->i_type = CONFIG_ITEM_INTEGER;
792 p_config->i_value = gtk_spin_button_get_value_as_int(
793 GTK_SPIN_BUTTON(editable) );
794 p_config->psz_name = (char *)gtk_object_get_data( GTK_OBJECT(editable),
797 g_hash_table_insert( hash_table, (gpointer)editable,
798 (gpointer)p_config );
800 /* change the highlight status of the Apply button */
801 apply_button = (GtkWidget *)gtk_object_get_data( GTK_OBJECT(user_data),
803 gtk_widget_set_sensitive( apply_button, TRUE );
806 /****************************************************************************
807 * GtkFloatChanged: signal called when the user changes a float value.
808 ****************************************************************************/
809 static void GtkFloatChanged( GtkEditable *editable, gpointer user_data )
811 intf_thread_t *p_intf;
812 module_config_t *p_config;
813 GHashTable *hash_table;
814 GtkWidget *apply_button;
816 p_intf = (intf_thread_t *)gtk_object_get_data( GTK_OBJECT(editable),
818 gtk_spin_button_update( GTK_SPIN_BUTTON(editable) );
820 hash_table = (GHashTable *)gtk_object_get_data( GTK_OBJECT(user_data),
821 "config_hash_table" );
823 /* free old p_config */
824 p_config = (module_config_t *)g_hash_table_lookup( hash_table,
825 (gpointer)editable );
826 if( p_config ) GtkFreeHashValue( NULL, (gpointer)p_config, (void *)p_intf );
828 p_config = malloc( sizeof(module_config_t) );
829 p_config->i_type = CONFIG_ITEM_FLOAT;
830 p_config->f_value = gtk_spin_button_get_value_as_float(
831 GTK_SPIN_BUTTON(editable) );
832 p_config->psz_name = (char *)gtk_object_get_data( GTK_OBJECT(editable),
835 g_hash_table_insert( hash_table, (gpointer)editable,
836 (gpointer)p_config );
838 /* change the highlight status of the Apply button */
839 apply_button = (GtkWidget *)gtk_object_get_data( GTK_OBJECT(user_data),
841 gtk_widget_set_sensitive( apply_button, TRUE );
844 /****************************************************************************
845 * GtkBoolChanged: signal called when the user changes a bool value.
846 ****************************************************************************/
847 static void GtkBoolChanged( GtkToggleButton *button, gpointer user_data )
849 intf_thread_t *p_intf;
850 module_config_t *p_config;
851 GHashTable *hash_table;
852 GtkWidget *apply_button;
854 p_intf = (intf_thread_t *)gtk_object_get_data( GTK_OBJECT(button),
856 hash_table = (GHashTable *)gtk_object_get_data( GTK_OBJECT(user_data),
857 "config_hash_table" );
859 /* free old p_config */
860 p_config = (module_config_t *)g_hash_table_lookup( hash_table,
862 if( p_config ) GtkFreeHashValue( NULL, (gpointer)p_config, (void *)p_intf );
864 p_config = malloc( sizeof(module_config_t) );
865 p_config->i_type = CONFIG_ITEM_BOOL;
866 p_config->i_value = gtk_toggle_button_get_active( button );
867 p_config->psz_name = (char *)gtk_object_get_data( GTK_OBJECT(button),
870 g_hash_table_insert( hash_table, (gpointer)button,
871 (gpointer)p_config );
873 /* change the highlight status of the Apply button */
874 apply_button = (GtkWidget *)gtk_object_get_data( GTK_OBJECT(user_data),
876 gtk_widget_set_sensitive( apply_button, TRUE );
879 /****************************************************************************
880 * GtkFreeHashTable: signal called when the config hash table is destroyed.
881 ****************************************************************************/
882 static void GtkFreeHashTable( GtkObject *object )
884 GHashTable *hash_table = (GHashTable *)gtk_object_get_data( object,
885 "config_hash_table" );
886 intf_thread_t *p_intf = (intf_thread_t *)gtk_object_get_data( object,
889 g_hash_table_foreach( hash_table, GtkFreeHashValue, (void *)p_intf );
890 g_hash_table_destroy( hash_table );
893 /****************************************************************************
894 * GtkFreeHashValue: signal called when an element of the config hash table
896 ****************************************************************************/
897 static void GtkFreeHashValue( gpointer key, gpointer value, gpointer user_data)
899 module_config_t * p_config = (module_config_t *)value;
901 if( p_config->i_type == CONFIG_ITEM_STRING )
902 if( p_config->psz_value ) g_free( p_config->psz_value );
906 /****************************************************************************
907 * GtkSaveHashValue: callback used when enumerating the hash table in
909 ****************************************************************************/
910 static gboolean GtkSaveHashValue( gpointer key, gpointer value,
913 intf_thread_t * p_intf = (intf_thread_t *)user_data;
914 module_config_t * p_config = (module_config_t *)value;
916 switch( p_config->i_type )
919 case CONFIG_ITEM_STRING:
920 case CONFIG_ITEM_FILE:
921 case CONFIG_ITEM_MODULE:
922 config_PutPsz( p_intf, p_config->psz_name,
923 *p_config->psz_value ? p_config->psz_value : NULL );
925 case CONFIG_ITEM_INTEGER:
926 case CONFIG_ITEM_BOOL:
927 config_PutInt( p_intf, p_config->psz_name, p_config->i_value );
929 case CONFIG_ITEM_FLOAT:
930 config_PutFloat( p_intf, p_config->psz_name, p_config->f_value );
934 /* free the hash value we allocated */
935 if( p_config->i_type == CONFIG_ITEM_STRING )
936 g_free( p_config->psz_value );
939 /* return TRUE so glib will free the hash entry */
943 /****************************************************************************
944 * GtkConfigDialogDestroyed: callback triggered when the config dialog box is
946 ****************************************************************************/
947 static void GtkConfigDialogDestroyed( GtkObject *object, gpointer user_data )
949 intf_thread_t *p_intf = (intf_thread_t *)user_data;
950 char *psz_module_name;
952 psz_module_name = gtk_object_get_data( object, "psz_module_name" );
954 /* remove the ref to the dialog box */
955 gtk_object_set_data( GTK_OBJECT(p_intf->p_sys->p_window),
956 psz_module_name, NULL );
958 GtkFreeHashTable( object );