1 /*****************************************************************************
2 * gtk_preferences.c: functions to handle the preferences dialog box.
3 *****************************************************************************
4 * Copyright (C) 2000, 2001 VideoLAN
5 * $Id: gtk_preferences.c,v 1.28 2002/05/18 13:30:28 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 */
37 #include <videolan/vlc.h>
39 #ifdef MODULE_NAME_IS_gnome
47 #include "interface.h"
49 #include "gtk_support.h"
50 #include "gtk_common.h"
51 #include "gtk_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 ( gpointer );
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 GtkPreferencesActivate( GtkMenuItem * menuitem, gpointer user_data )
82 intf_thread_t * p_intf;
84 p_intf = GetIntf( GTK_WIDGET(menuitem), (char*)user_data );
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 *p_module, *p_module_bis;
122 module_config_t *p_item;
126 GHashTable *config_hash_table;
128 GtkWidget *item_event_box;
130 GtkWidget *config_dialog;
131 GtkWidget *config_dialog_vbox;
132 GtkWidget *config_notebook;
134 GtkWidget *category_table = NULL;
135 GtkWidget *category_label = NULL;
137 #ifndef MODULE_NAME_IS_gnome
138 GtkWidget *dialog_action_area;
141 GtkWidget *ok_button;
142 GtkWidget *apply_button;
143 GtkWidget *save_button;
144 GtkWidget *cancel_button;
146 GtkWidget *item_align;
147 GtkWidget *item_frame;
148 GtkWidget *item_hbox;
149 GtkWidget *item_label;
150 GtkWidget *item_vbox;
151 GtkWidget *string_entry;
152 GtkWidget *integer_spinbutton;
153 GtkWidget *float_spinbutton;
155 GtkWidget *bool_checkbutton;
156 GtkWidget *module_clist;
157 GtkWidget *module_config_button;
158 GtkWidget *module_select_button;
160 gint category_max_height;
162 /* Check if the dialog box is already opened, if so this will save us
163 * quite a bit of work. (the interface will be destroyed when you actually
164 * close the dialog window, but remember that it is only hidden if you
165 * clicked on the action buttons). This trick also allows us not to
166 * duplicate identical dialog windows. */
168 config_dialog = (GtkWidget *)gtk_object_get_data(
169 GTK_OBJECT(p_intf->p_sys->p_window), psz_module_name );
172 /* Yeah it was open */
173 gtk_widget_show( config_dialog );
174 gtk_widget_grab_focus( config_dialog );
179 /* Look for the selected module */
180 for( p_module = p_module_bank->first ; p_module != NULL ;
181 p_module = p_module->next )
184 if( psz_module_name && !strcmp( psz_module_name, p_module->psz_name ) )
187 if( !p_module ) return;
189 /* We found it, now we can start building its configuration interface */
190 /* Create the configuration dialog box */
192 #ifdef MODULE_NAME_IS_gnome
193 config_dialog = gnome_dialog_new( p_module->psz_longname, NULL );
194 config_dialog_vbox = GNOME_DIALOG(config_dialog)->vbox;
196 config_dialog = gtk_dialog_new();
197 gtk_window_set_title( GTK_WINDOW(config_dialog), p_module->psz_longname );
198 config_dialog_vbox = GTK_DIALOG(config_dialog)->vbox;
201 category_max_height = config_GetIntVariable( MODULE_STRING "-prefs-maxh" );
203 gtk_window_set_policy( GTK_WINDOW(config_dialog), TRUE, TRUE, FALSE );
204 gtk_container_set_border_width( GTK_CONTAINER(config_dialog_vbox), 0 );
206 /* Create our config hash table and associate it with the dialog box */
207 config_hash_table = g_hash_table_new( NULL, NULL );
208 gtk_object_set_data_full( GTK_OBJECT(config_dialog),
209 "config_hash_table", config_hash_table,
210 (GtkDestroyNotify)GtkFreeHashTable );
212 /* Create notebook */
213 config_notebook = gtk_notebook_new();
214 gtk_notebook_set_scrollable( GTK_NOTEBOOK(config_notebook), TRUE );
215 gtk_container_add( GTK_CONTAINER(config_dialog_vbox), config_notebook );
217 /* Enumerate config options and add corresponding config boxes */
218 p_item = p_module->p_config;
221 switch( p_item->i_type )
224 case MODULE_CONFIG_HINT_CATEGORY:
225 case MODULE_CONFIG_HINT_END:
228 * Before we start building the interface for the new category, we
229 * must close/finish the previous one we were generating.
233 GtkWidget *_scrolled_window;
234 GtkWidget *_viewport;
236 GtkRequisition _requisition;
238 /* create a vbox to deal with EXPAND/FILL issues in the
239 * notebook page, and pack it with the previously generated
241 _vbox = gtk_vbox_new( FALSE, 0 );
242 gtk_container_set_border_width( GTK_CONTAINER(_vbox), 4 );
243 gtk_box_pack_start( GTK_BOX(_vbox), category_table,
246 /* create a new scrolled window that will contain all of the
248 _scrolled_window = gtk_scrolled_window_new( NULL, NULL );
249 gtk_scrolled_window_set_policy(
250 GTK_SCROLLED_WINDOW(_scrolled_window), GTK_POLICY_NEVER,
251 GTK_POLICY_AUTOMATIC );
252 /* add scrolled window as a notebook page */
253 gtk_notebook_append_page( GTK_NOTEBOOK(config_notebook),
254 _scrolled_window, category_label );
255 /* pack the vbox into the scrolled window */
256 _viewport = gtk_viewport_new( NULL, NULL );
257 gtk_viewport_set_shadow_type( GTK_VIEWPORT(_viewport),
259 gtk_container_add( GTK_CONTAINER(_viewport), _vbox );
260 gtk_container_add( GTK_CONTAINER(_scrolled_window),
263 /* set the size of the scrolled window to the size of the
265 gtk_widget_show_all( _vbox );
266 gtk_widget_size_request( _vbox, &_requisition );
267 if( _requisition.height > category_max_height )
268 gtk_widget_set_usize( _scrolled_window, -1,
269 category_max_height );
271 gtk_widget_set_usize( _scrolled_window, -1,
272 _requisition.height );
277 * Now we can start taking care of the new category
280 if( p_item->i_type == MODULE_CONFIG_HINT_CATEGORY )
282 /* create a new table for right-left alignment of children */
283 category_table = gtk_table_new( 0, 0, FALSE );
284 gtk_table_set_col_spacings( GTK_TABLE(category_table), 4 );
287 /* create a new category label */
288 category_label = gtk_label_new( p_item->psz_text );
293 case MODULE_CONFIG_ITEM_MODULE:
295 item_frame = gtk_frame_new( p_item->psz_text );
297 gtk_table_resize( GTK_TABLE(category_table), ++rows, 2 );
298 gtk_table_attach_defaults( GTK_TABLE(category_table), item_frame,
299 0, 2, rows - 1, rows );
301 item_vbox = gtk_vbox_new( FALSE, 4 );
302 gtk_container_add( GTK_CONTAINER(item_frame), item_vbox );
304 /* create a new clist widget */
306 gchar * titles[] = { _("Name"), _("Description") };
309 gtk_clist_new_with_titles( 2, titles );
311 gtk_clist_column_titles_passive( GTK_CLIST(module_clist) );
312 gtk_clist_set_selection_mode( GTK_CLIST(module_clist),
313 GTK_SELECTION_SINGLE);
314 gtk_container_add( GTK_CONTAINER(item_vbox), module_clist );
316 /* build a list of available modules */
320 for( p_module_bis = p_module_bank->first ;
321 p_module_bis != NULL ;
322 p_module_bis = p_module_bis->next )
324 if( p_module_bis->i_capabilities & (1 << p_item->i_value) )
326 entry[0] = p_module_bis->psz_name;
327 entry[1] = p_module_bis->psz_longname;
328 gtk_clist_append( GTK_CLIST(module_clist), entry );
333 gtk_clist_set_column_auto_resize( GTK_CLIST(module_clist),
335 gtk_clist_set_column_auto_resize( GTK_CLIST(module_clist),
338 /* connect signals to the modules list */
339 gtk_signal_connect( GTK_OBJECT(module_clist), "select_row",
340 GTK_SIGNAL_FUNC(GtkModuleHighlighted),
343 /* hbox holding the "select" and "configure" buttons */
344 item_hbox = gtk_hbox_new( FALSE, 4 );
345 gtk_container_add( GTK_CONTAINER(item_vbox), item_hbox);
347 /* add configure button */
348 module_config_button =
349 gtk_button_new_with_label( _("Configure") );
350 gtk_widget_set_sensitive( module_config_button, FALSE );
351 gtk_container_add( GTK_CONTAINER(item_hbox),
352 module_config_button );
353 gtk_object_set_data( GTK_OBJECT(module_config_button),
355 gtk_object_set_data( GTK_OBJECT(module_clist),
356 "config_button", module_config_button );
358 /* add select button */
359 module_select_button =
360 gtk_button_new_with_label( _("Select") );
361 gtk_container_add( GTK_CONTAINER(item_hbox),
362 module_select_button );
363 /* add a tooltip on mouseover */
364 gtk_tooltips_set_tip( p_intf->p_sys->p_tooltips,
365 module_select_button,
366 p_item->psz_longtext, "" );
368 /* hbox holding the "selected" label and text input */
369 item_hbox = gtk_hbox_new( FALSE, 4 );
370 gtk_container_add( GTK_CONTAINER(item_vbox), item_hbox);
372 item_label = gtk_label_new( _("Selected:") );
373 gtk_container_add( GTK_CONTAINER(item_hbox), item_label );
375 /* add input box with default value */
376 string_entry = gtk_entry_new();
377 gtk_object_set_data( GTK_OBJECT(module_clist),
378 "module_entry", string_entry );
379 gtk_container_add( GTK_CONTAINER(item_hbox), string_entry );
380 vlc_mutex_lock( p_item->p_lock );
381 gtk_entry_set_text( GTK_ENTRY(string_entry),
382 p_item->psz_value ? p_item->psz_value : "" );
383 vlc_mutex_unlock( p_item->p_lock );
384 /* add a tooltip on mouseover */
385 gtk_tooltips_set_tip( p_intf->p_sys->p_tooltips,
386 string_entry, p_item->psz_longtext, "" );
388 /* connect signals to the buttons */
389 gtk_signal_connect( GTK_OBJECT(module_config_button), "clicked",
390 GTK_SIGNAL_FUNC(GtkModuleConfigure),
391 (gpointer)module_clist );
392 gtk_signal_connect( GTK_OBJECT(module_select_button), "clicked",
393 GTK_SIGNAL_FUNC(GtkModuleSelected),
394 (gpointer)module_clist );
396 /* connect signal to track changes in the text box */
397 gtk_object_set_data( GTK_OBJECT(string_entry), "config_option",
399 gtk_signal_connect( GTK_OBJECT(string_entry), "changed",
400 GTK_SIGNAL_FUNC(GtkStringChanged),
401 (gpointer)config_dialog );
404 case MODULE_CONFIG_ITEM_STRING:
405 case MODULE_CONFIG_ITEM_FILE:
407 /* add input box with default value */
408 string_entry = gtk_entry_new();
409 vlc_mutex_lock( p_item->p_lock );
410 gtk_entry_set_text( GTK_ENTRY(string_entry),
411 p_item->psz_value ? p_item->psz_value : "" );
412 vlc_mutex_unlock( p_item->p_lock );
414 /* connect signal to track changes in the text box */
415 gtk_object_set_data( GTK_OBJECT(string_entry), "config_option",
417 gtk_signal_connect( GTK_OBJECT(string_entry), "changed",
418 GTK_SIGNAL_FUNC(GtkStringChanged),
419 (gpointer)config_dialog );
421 LABEL_AND_WIDGET( p_item->psz_text,
422 string_entry, p_item->psz_longtext );
425 case MODULE_CONFIG_ITEM_INTEGER:
427 /* add input box with default value */
428 item_adj = gtk_adjustment_new( p_item->i_value,
429 -1, 99999, 1, 10, 10 );
430 integer_spinbutton = gtk_spin_button_new( GTK_ADJUSTMENT(item_adj),
433 /* connect signal to track changes in the spinbutton value */
434 gtk_object_set_data( GTK_OBJECT(integer_spinbutton),
435 "config_option", p_item->psz_name );
436 gtk_signal_connect( GTK_OBJECT(integer_spinbutton), "changed",
437 GTK_SIGNAL_FUNC(GtkIntChanged),
438 (gpointer)config_dialog );
440 LABEL_AND_WIDGET( p_item->psz_text,
441 integer_spinbutton, p_item->psz_longtext );
444 case MODULE_CONFIG_ITEM_FLOAT:
446 /* add input box with default value */
447 item_adj = gtk_adjustment_new( p_item->f_value,
448 0, 99999, 0.01, 10, 10 );
449 float_spinbutton = gtk_spin_button_new( GTK_ADJUSTMENT(item_adj),
452 /* connect signal to track changes in the spinbutton value */
453 gtk_object_set_data( GTK_OBJECT(float_spinbutton),
454 "config_option", p_item->psz_name );
455 gtk_signal_connect( GTK_OBJECT(float_spinbutton), "changed",
456 GTK_SIGNAL_FUNC(GtkFloatChanged),
457 (gpointer)config_dialog );
459 LABEL_AND_WIDGET( p_item->psz_text,
460 float_spinbutton, p_item->psz_longtext );
463 case MODULE_CONFIG_ITEM_BOOL:
465 /* add check button */
466 bool_checkbutton = gtk_check_button_new();
467 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(bool_checkbutton),
470 /* connect signal to track changes in the button state */
471 gtk_object_set_data( GTK_OBJECT(bool_checkbutton), "config_option",
473 gtk_signal_connect( GTK_OBJECT(bool_checkbutton), "toggled",
474 GTK_SIGNAL_FUNC(GtkBoolChanged),
475 (gpointer)config_dialog );
477 LABEL_AND_WIDGET( p_item->psz_text,
478 bool_checkbutton, p_item->psz_longtext );
484 while( p_item->i_type != MODULE_CONFIG_HINT_END && p_item++ );
486 #ifndef MODULE_NAME_IS_gnome
487 /* Now let's add the action buttons at the bottom of the page */
488 dialog_action_area = GTK_DIALOG(config_dialog)->action_area;
489 gtk_container_set_border_width( GTK_CONTAINER(dialog_action_area), 4 );
491 /* add a new table for the config option */
492 item_hbox = gtk_hbox_new( FALSE, 0 );
493 gtk_box_pack_end( GTK_BOX(dialog_action_area), item_hbox,
495 item_hbox = gtk_hbox_new( FALSE, 0 );
496 gtk_box_pack_end( GTK_BOX(dialog_action_area), item_hbox,
500 /* Create the OK button */
501 #ifdef MODULE_NAME_IS_gnome
502 gnome_dialog_append_button( GNOME_DIALOG(config_dialog),
503 GNOME_STOCK_BUTTON_OK );
505 GTK_WIDGET(g_list_last(GNOME_DIALOG(config_dialog)->buttons)->data);
507 gnome_dialog_append_button( GNOME_DIALOG(config_dialog),
508 GNOME_STOCK_BUTTON_APPLY );
510 GTK_WIDGET(g_list_last(GNOME_DIALOG(config_dialog)->buttons)->data);
512 gnome_dialog_append_button_with_pixmap(
513 GNOME_DIALOG(config_dialog), _("Save"), GNOME_STOCK_PIXMAP_SAVE );
515 GTK_WIDGET(g_list_last(GNOME_DIALOG(config_dialog)->buttons)->data);
517 gnome_dialog_append_button( GNOME_DIALOG(config_dialog),
518 GNOME_STOCK_BUTTON_CANCEL );
520 GTK_WIDGET(g_list_last(GNOME_DIALOG(config_dialog)->buttons)->data);
522 ok_button = gtk_button_new_with_label( _("OK") );
523 gtk_box_pack_start( GTK_BOX(dialog_action_area), ok_button,
526 apply_button = gtk_button_new_with_label( _("Apply") );
527 gtk_box_pack_start( GTK_BOX(dialog_action_area), apply_button,
530 save_button = gtk_button_new_with_label( _("Save") );
531 gtk_box_pack_start( GTK_BOX(dialog_action_area), save_button,
534 cancel_button = gtk_button_new_with_label( _("Cancel") );
535 gtk_box_pack_start( GTK_BOX(dialog_action_area), cancel_button,
539 gtk_signal_connect( GTK_OBJECT(ok_button), "clicked",
540 GTK_SIGNAL_FUNC(GtkConfigOk),
542 gtk_widget_set_sensitive( apply_button, FALSE );
543 gtk_object_set_data( GTK_OBJECT(config_dialog), "apply_button",
545 gtk_signal_connect( GTK_OBJECT(apply_button), "clicked",
546 GTK_SIGNAL_FUNC(GtkConfigApply),
548 gtk_signal_connect( GTK_OBJECT(save_button), "clicked",
549 GTK_SIGNAL_FUNC(GtkConfigSave),
551 gtk_signal_connect( GTK_OBJECT(cancel_button), "clicked",
552 GTK_SIGNAL_FUNC(GtkConfigCancel),
557 /* Ok, job done successfully. Let's keep a reference to the dialog box */
558 gtk_object_set_data( GTK_OBJECT(p_intf->p_sys->p_window),
559 psz_module_name, config_dialog );
560 gtk_object_set_data( GTK_OBJECT(config_dialog), "psz_module_name",
563 /* we want this ref to be destroyed if the object is destroyed */
564 gtk_signal_connect( GTK_OBJECT(config_dialog), "destroy",
565 GTK_SIGNAL_FUNC(GtkConfigDialogDestroyed),
568 gtk_widget_show_all( config_dialog );
571 #undef LABEL_AND_WIDGET
574 /****************************************************************************
575 * GtkConfigApply: store the changes to the config inside the modules
576 * configuration structure and clear the hash table.
577 ****************************************************************************/
578 void GtkConfigApply( GtkButton * button, gpointer user_data )
580 GHashTable *hash_table;
581 GtkWidget *apply_button;
583 hash_table = (GHashTable *)gtk_object_get_data( GTK_OBJECT(user_data),
584 "config_hash_table" );
585 g_hash_table_foreach_remove( hash_table, GtkSaveHashValue, NULL );
587 /* change the highlight status of the Apply button */
588 apply_button = (GtkWidget *)gtk_object_get_data( GTK_OBJECT(user_data),
590 gtk_widget_set_sensitive( apply_button, FALSE );
594 void GtkConfigOk( GtkButton * button, gpointer user_data )
596 GtkConfigApply( button, user_data );
597 gtk_widget_hide( gtk_widget_get_toplevel( GTK_WIDGET (button) ) );
601 void GtkConfigCancel( GtkButton * button, gpointer user_data )
603 gtk_widget_hide( gtk_widget_get_toplevel( GTK_WIDGET (button) ) );
606 void GtkConfigSave( GtkButton * button, gpointer user_data )
608 GtkConfigApply( button, user_data );
609 config_SaveConfigFile( NULL );
612 /****************************************************************************
613 * GtkModuleHighlighted: display module description when an entry is selected
614 * in the clist, and activate the configure button if necessary.
615 ****************************************************************************/
616 void GtkModuleHighlighted( GtkCList *module_clist, int row, int column,
617 GdkEventButton *event, gpointer user_data )
619 GtkWidget *config_button;
623 if( gtk_clist_get_text( GTK_CLIST(module_clist), row, 0, &psz_name ) )
625 /* look for module 'psz_name' */
626 for( p_module = p_module_bank->first ;
628 p_module = p_module->next )
630 if( !strcmp( p_module->psz_name, psz_name ) )
632 gtk_object_set_data( GTK_OBJECT(module_clist),
633 "module_highlighted", p_module );
634 config_button = gtk_object_get_data( GTK_OBJECT(module_clist),
636 if( p_module->i_config_items )
637 gtk_widget_set_sensitive( config_button, TRUE );
639 gtk_widget_set_sensitive( config_button, FALSE );
648 /****************************************************************************
649 * GtkModuleConfigure: display module configuration dialog box.
650 ****************************************************************************/
651 void GtkModuleConfigure( GtkButton *button, gpointer user_data )
654 intf_thread_t *p_intf;
656 p_module = (module_t *)gtk_object_get_data( GTK_OBJECT(user_data),
657 "module_highlighted" );
659 if( !p_module ) return;
660 p_intf = (intf_thread_t *)gtk_object_get_data( GTK_OBJECT(button),
662 GtkCreateConfigDialog( p_module->psz_name, (gpointer)p_intf );
666 /****************************************************************************
667 * GtkModuleSelected: select module.
668 ****************************************************************************/
669 void GtkModuleSelected( GtkButton *button, gpointer user_data )
674 p_module = (module_t *)gtk_object_get_data( GTK_OBJECT(user_data),
675 "module_highlighted" );
676 widget = (GtkWidget *)gtk_object_get_data( GTK_OBJECT(user_data),
678 if( !p_module ) return;
680 gtk_entry_set_text( GTK_ENTRY(widget), p_module->psz_name );
684 /****************************************************************************
685 * GtkStringChanged: signal called when the user changes a string value.
686 ****************************************************************************/
687 static void GtkStringChanged( GtkEditable *editable, gpointer user_data )
689 module_config_t *p_config;
691 GHashTable *hash_table;
692 GtkWidget *apply_button;
694 hash_table = (GHashTable *)gtk_object_get_data( GTK_OBJECT(user_data),
695 "config_hash_table" );
696 /* free old p_config */
697 p_config = (module_config_t *)g_hash_table_lookup( hash_table,
698 (gpointer)editable );
699 if( p_config ) GtkFreeHashValue( NULL, (gpointer)p_config, NULL );
701 p_config = malloc( sizeof(module_config_t) );
702 p_config->i_type = MODULE_CONFIG_ITEM_STRING;
703 p_config->psz_value = gtk_editable_get_chars( editable, 0, -1 );
704 p_config->psz_name = (char *)gtk_object_get_data( GTK_OBJECT(editable),
707 g_hash_table_insert( hash_table, (gpointer)editable,
708 (gpointer)p_config );
710 /* change the highlight status of the Apply button */
711 apply_button = (GtkWidget *)gtk_object_get_data( GTK_OBJECT(user_data),
713 gtk_widget_set_sensitive( apply_button, TRUE );
716 /****************************************************************************
717 * GtkIntChanged: signal called when the user changes an integer value.
718 ****************************************************************************/
719 static void GtkIntChanged( GtkEditable *editable, gpointer user_data )
721 module_config_t *p_config;
723 GHashTable *hash_table;
724 GtkWidget *apply_button;
726 hash_table = (GHashTable *)gtk_object_get_data( GTK_OBJECT(user_data),
727 "config_hash_table" );
729 /* free old p_config */
730 p_config = (module_config_t *)g_hash_table_lookup( hash_table,
731 (gpointer)editable );
732 if( p_config ) GtkFreeHashValue( NULL, (gpointer)p_config, NULL );
734 p_config = malloc( sizeof(module_config_t) );
735 p_config->i_type = MODULE_CONFIG_ITEM_INTEGER;
736 gtk_spin_button_update( GTK_SPIN_BUTTON(editable) );
737 p_config->i_value = gtk_spin_button_get_value_as_int(
738 GTK_SPIN_BUTTON(editable) );
739 p_config->psz_name = (char *)gtk_object_get_data( GTK_OBJECT(editable),
742 g_hash_table_insert( hash_table, (gpointer)editable,
743 (gpointer)p_config );
745 /* change the highlight status of the Apply button */
746 apply_button = (GtkWidget *)gtk_object_get_data( GTK_OBJECT(user_data),
748 gtk_widget_set_sensitive( apply_button, TRUE );
751 /****************************************************************************
752 * GtkFloatChanged: signal called when the user changes a float value.
753 ****************************************************************************/
754 static void GtkFloatChanged( GtkEditable *editable, gpointer user_data )
756 module_config_t *p_config;
758 GHashTable *hash_table;
759 GtkWidget *apply_button;
761 hash_table = (GHashTable *)gtk_object_get_data( GTK_OBJECT(user_data),
762 "config_hash_table" );
764 /* free old p_config */
765 p_config = (module_config_t *)g_hash_table_lookup( hash_table,
766 (gpointer)editable );
767 if( p_config ) GtkFreeHashValue( NULL, (gpointer)p_config, NULL );
769 p_config = malloc( sizeof(module_config_t) );
770 p_config->i_type = MODULE_CONFIG_ITEM_FLOAT;
771 gtk_spin_button_update( GTK_SPIN_BUTTON(editable) );
772 p_config->f_value = gtk_spin_button_get_value_as_float(
773 GTK_SPIN_BUTTON(editable) );
774 p_config->psz_name = (char *)gtk_object_get_data( GTK_OBJECT(editable),
777 g_hash_table_insert( hash_table, (gpointer)editable,
778 (gpointer)p_config );
780 /* change the highlight status of the Apply button */
781 apply_button = (GtkWidget *)gtk_object_get_data( GTK_OBJECT(user_data),
783 gtk_widget_set_sensitive( apply_button, TRUE );
786 /****************************************************************************
787 * GtkStringChanged: signal called when the user changes a bool value.
788 ****************************************************************************/
789 static void GtkBoolChanged( GtkToggleButton *button, gpointer user_data )
791 module_config_t *p_config;
793 GHashTable *hash_table;
794 GtkWidget *apply_button;
796 hash_table = (GHashTable *)gtk_object_get_data( GTK_OBJECT(user_data),
797 "config_hash_table" );
799 /* free old p_config */
800 p_config = (module_config_t *)g_hash_table_lookup( hash_table,
802 if( p_config ) GtkFreeHashValue( NULL, (gpointer)p_config, NULL );
804 p_config = malloc( sizeof(module_config_t) );
805 p_config->i_type = MODULE_CONFIG_ITEM_BOOL;
806 p_config->i_value = gtk_toggle_button_get_active( button );
807 p_config->psz_name = (char *)gtk_object_get_data( GTK_OBJECT(button),
810 g_hash_table_insert( hash_table, (gpointer)button,
811 (gpointer)p_config );
813 /* change the highlight status of the Apply button */
814 apply_button = (GtkWidget *)gtk_object_get_data( GTK_OBJECT(user_data),
816 gtk_widget_set_sensitive( apply_button, TRUE );
819 /****************************************************************************
820 * GtkFreeHashTable: signal called when the config hash table is destroyed.
821 ****************************************************************************/
822 static void GtkFreeHashTable( gpointer user_data )
824 GHashTable *hash_table = (GHashTable *)user_data;
826 g_hash_table_foreach( hash_table, GtkFreeHashValue, NULL );
827 g_hash_table_destroy( hash_table );
830 /****************************************************************************
831 * GtkFreeHashValue: signal called when an element of the config hash table
833 ****************************************************************************/
834 static void GtkFreeHashValue( gpointer key, gpointer value, gpointer user_data)
836 module_config_t *p_config = (module_config_t *)value;
838 if( p_config->i_type == MODULE_CONFIG_ITEM_STRING )
839 g_free( p_config->psz_value );
843 /****************************************************************************
844 * GtkSaveHashValue: callback used when enumerating the hash table in
846 ****************************************************************************/
847 static gboolean GtkSaveHashValue( gpointer key, gpointer value,
850 module_config_t *p_config = (module_config_t *)value;
852 switch( p_config->i_type )
855 case MODULE_CONFIG_ITEM_STRING:
856 case MODULE_CONFIG_ITEM_FILE:
857 case MODULE_CONFIG_ITEM_MODULE:
858 config_PutPszVariable( p_config->psz_name,
859 *p_config->psz_value? p_config->psz_value : NULL );
861 case MODULE_CONFIG_ITEM_INTEGER:
862 case MODULE_CONFIG_ITEM_BOOL:
863 config_PutIntVariable( p_config->psz_name, p_config->i_value );
865 case MODULE_CONFIG_ITEM_FLOAT:
866 config_PutFloatVariable( p_config->psz_name, p_config->f_value );
870 /* free the hash value we allocated */
871 if( p_config->i_type == MODULE_CONFIG_ITEM_STRING )
872 g_free( p_config->psz_value );
875 /* return TRUE so glib will free the hash entry */
879 /****************************************************************************
880 * GtkConfigDialogDestroyed: callback triggered when the config dialog box is
882 ****************************************************************************/
883 static void GtkConfigDialogDestroyed( GtkObject *object, gpointer user_data )
885 intf_thread_t *p_intf = (intf_thread_t *)user_data;
886 char *psz_module_name;
888 psz_module_name = gtk_object_get_data( object, "psz_module_name" );
890 /* remove the ref to the dialog box */
891 gtk_object_set_data( GTK_OBJECT(p_intf->p_sys->p_window),
892 psz_module_name, NULL );