1 /* Hey EMACS -*- linux-c -*- */
4 * Copyright (C) 2002-2003 Romain Lievin <roms@tilp.info>
5 * Released under the terms of the GNU GPL v2.0.
16 #include <glade/glade.h>
19 #include <gdk/gdkkeysyms.h>
30 SINGLE_VIEW
, SPLIT_VIEW
, FULL_VIEW
33 static gint view_mode
= FULL_VIEW
;
34 static gboolean show_name
= TRUE
;
35 static gboolean show_range
= TRUE
;
36 static gboolean show_value
= TRUE
;
37 static gboolean show_all
= FALSE
;
38 static gboolean show_debug
= FALSE
;
39 static gboolean resizeable
= FALSE
;
41 GtkWidget
*main_wnd
= NULL
;
42 GtkWidget
*tree1_w
= NULL
; // left frame
43 GtkWidget
*tree2_w
= NULL
; // right frame
44 GtkWidget
*text_w
= NULL
;
45 GtkWidget
*hpaned
= NULL
;
46 GtkWidget
*vpaned
= NULL
;
47 GtkWidget
*back_btn
= NULL
;
48 GtkWidget
*save_btn
= NULL
;
49 GtkWidget
*save_menu_item
= NULL
;
51 GtkTextTag
*tag1
, *tag2
;
54 GtkTreeStore
*tree1
, *tree2
, *tree
;
55 GtkTreeModel
*model1
, *model2
;
56 static GtkTreeIter
*parents
[256];
59 static struct menu
*current
; // current node for SINGLE view
60 static struct menu
*browsed
; // browsed node for SPLIT view
63 COL_OPTION
, COL_NAME
, COL_NO
, COL_MOD
, COL_YES
, COL_VALUE
,
64 COL_MENU
, COL_COLOR
, COL_EDIT
, COL_PIXBUF
,
65 COL_PIXVIS
, COL_BTNVIS
, COL_BTNACT
, COL_BTNINC
, COL_BTNRAD
,
69 static void display_list(void);
70 static void display_tree(struct menu
*menu
);
71 static void display_tree_part(void);
72 static void update_tree(struct menu
*src
, GtkTreeIter
* dst
);
73 static void set_node(GtkTreeIter
* node
, struct menu
*menu
, gchar
** row
);
74 static gchar
**fill_row(struct menu
*menu
);
75 static void conf_changed(void);
77 /* Helping/Debugging Functions */
80 const char *dbg_print_stype(int val
)
87 strcpy(buf
, "unknown");
89 strcpy(buf
, "boolean");
90 if (val
== S_TRISTATE
)
91 strcpy(buf
, "tristate");
97 strcpy(buf
, "string");
108 const char *dbg_print_flags(int val
)
110 static char buf
[256];
114 if (val
& SYMBOL_CONST
)
115 strcat(buf
, "const/");
116 if (val
& SYMBOL_CHECK
)
117 strcat(buf
, "check/");
118 if (val
& SYMBOL_CHOICE
)
119 strcat(buf
, "choice/");
120 if (val
& SYMBOL_CHOICEVAL
)
121 strcat(buf
, "choiceval/");
122 if (val
& SYMBOL_PRINTED
)
123 strcat(buf
, "printed/");
124 if (val
& SYMBOL_VALID
)
125 strcat(buf
, "valid/");
126 if (val
& SYMBOL_OPTIONAL
)
127 strcat(buf
, "optional/");
128 if (val
& SYMBOL_WRITE
)
129 strcat(buf
, "write/");
130 if (val
& SYMBOL_CHANGED
)
131 strcat(buf
, "changed/");
132 if (val
& SYMBOL_AUTO
)
133 strcat(buf
, "auto/");
135 buf
[strlen(buf
) - 1] = '\0';
143 const char *dbg_print_ptype(int val
)
145 static char buf
[256];
149 if (val
== P_UNKNOWN
)
150 strcpy(buf
, "unknown");
152 strcpy(buf
, "prompt");
153 if (val
== P_COMMENT
)
154 strcpy(buf
, "comment");
157 if (val
== P_DEFAULT
)
158 strcpy(buf
, "default");
160 strcpy(buf
, "choice");
170 void replace_button_icon(GladeXML
* xml
, GdkDrawable
* window
,
171 GtkStyle
* style
, gchar
* btn_name
, gchar
** xpm
)
175 GtkToolButton
*button
;
178 pixmap
= gdk_pixmap_create_from_xpm_d(window
, &mask
,
179 &style
->bg
[GTK_STATE_NORMAL
],
182 button
= GTK_TOOL_BUTTON(glade_xml_get_widget(xml
, btn_name
));
183 image
= gtk_image_new_from_pixmap(pixmap
, mask
);
184 gtk_widget_show(image
);
185 gtk_tool_button_set_icon_widget(button
, image
);
188 /* Main Window Initialization */
189 void init_main_window(const gchar
* glade_file
)
193 GtkTextBuffer
*txtbuf
;
197 xml
= glade_xml_new(glade_file
, "window1", NULL
);
199 g_error(_("GUI loading failed !\n"));
200 glade_xml_signal_autoconnect(xml
);
202 main_wnd
= glade_xml_get_widget(xml
, "window1");
203 hpaned
= glade_xml_get_widget(xml
, "hpaned1");
204 vpaned
= glade_xml_get_widget(xml
, "vpaned1");
205 tree1_w
= glade_xml_get_widget(xml
, "treeview1");
206 tree2_w
= glade_xml_get_widget(xml
, "treeview2");
207 text_w
= glade_xml_get_widget(xml
, "textview3");
209 back_btn
= glade_xml_get_widget(xml
, "button1");
210 gtk_widget_set_sensitive(back_btn
, FALSE
);
212 widget
= glade_xml_get_widget(xml
, "show_name1");
213 gtk_check_menu_item_set_active((GtkCheckMenuItem
*) widget
,
216 widget
= glade_xml_get_widget(xml
, "show_range1");
217 gtk_check_menu_item_set_active((GtkCheckMenuItem
*) widget
,
220 widget
= glade_xml_get_widget(xml
, "show_data1");
221 gtk_check_menu_item_set_active((GtkCheckMenuItem
*) widget
,
224 save_btn
= glade_xml_get_widget(xml
, "button3");
225 save_menu_item
= glade_xml_get_widget(xml
, "save1");
226 conf_set_changed_callback(conf_changed
);
228 style
= gtk_widget_get_style(main_wnd
);
229 widget
= glade_xml_get_widget(xml
, "toolbar1");
231 #if 0 /* Use stock Gtk icons instead */
232 replace_button_icon(xml
, main_wnd
->window
, style
,
233 "button1", (gchar
**) xpm_back
);
234 replace_button_icon(xml
, main_wnd
->window
, style
,
235 "button2", (gchar
**) xpm_load
);
236 replace_button_icon(xml
, main_wnd
->window
, style
,
237 "button3", (gchar
**) xpm_save
);
239 replace_button_icon(xml
, main_wnd
->window
, style
,
240 "button4", (gchar
**) xpm_single_view
);
241 replace_button_icon(xml
, main_wnd
->window
, style
,
242 "button5", (gchar
**) xpm_split_view
);
243 replace_button_icon(xml
, main_wnd
->window
, style
,
244 "button6", (gchar
**) xpm_tree_view
);
249 widget
= glade_xml_get_widget(xml
, "button4");
250 g_signal_emit_by_name(widget
, "clicked");
253 widget
= glade_xml_get_widget(xml
, "button5");
254 g_signal_emit_by_name(widget
, "clicked");
257 widget
= glade_xml_get_widget(xml
, "button6");
258 g_signal_emit_by_name(widget
, "clicked");
262 txtbuf
= gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w
));
263 tag1
= gtk_text_buffer_create_tag(txtbuf
, "mytag1",
265 "weight", PANGO_WEIGHT_BOLD
,
267 tag2
= gtk_text_buffer_create_tag(txtbuf
, "mytag2",
268 /*"style", PANGO_STYLE_OBLIQUE, */
271 sprintf(title
, _("Linux Kernel v%s Configuration"),
272 getenv("KERNELVERSION"));
273 gtk_window_set_title(GTK_WINDOW(main_wnd
), title
);
275 gtk_widget_show(main_wnd
);
278 void init_tree_model(void)
282 tree
= tree2
= gtk_tree_store_new(COL_NUMBER
,
283 G_TYPE_STRING
, G_TYPE_STRING
,
284 G_TYPE_STRING
, G_TYPE_STRING
,
285 G_TYPE_STRING
, G_TYPE_STRING
,
286 G_TYPE_POINTER
, GDK_TYPE_COLOR
,
287 G_TYPE_BOOLEAN
, GDK_TYPE_PIXBUF
,
288 G_TYPE_BOOLEAN
, G_TYPE_BOOLEAN
,
289 G_TYPE_BOOLEAN
, G_TYPE_BOOLEAN
,
291 model2
= GTK_TREE_MODEL(tree2
);
293 for (parents
[0] = NULL
, i
= 1; i
< 256; i
++)
294 parents
[i
] = (GtkTreeIter
*) g_malloc(sizeof(GtkTreeIter
));
296 tree1
= gtk_tree_store_new(COL_NUMBER
,
297 G_TYPE_STRING
, G_TYPE_STRING
,
298 G_TYPE_STRING
, G_TYPE_STRING
,
299 G_TYPE_STRING
, G_TYPE_STRING
,
300 G_TYPE_POINTER
, GDK_TYPE_COLOR
,
301 G_TYPE_BOOLEAN
, GDK_TYPE_PIXBUF
,
302 G_TYPE_BOOLEAN
, G_TYPE_BOOLEAN
,
303 G_TYPE_BOOLEAN
, G_TYPE_BOOLEAN
,
305 model1
= GTK_TREE_MODEL(tree1
);
308 void init_left_tree(void)
310 GtkTreeView
*view
= GTK_TREE_VIEW(tree1_w
);
311 GtkCellRenderer
*renderer
;
312 GtkTreeSelection
*sel
;
313 GtkTreeViewColumn
*column
;
315 gtk_tree_view_set_model(view
, model1
);
316 gtk_tree_view_set_headers_visible(view
, TRUE
);
317 gtk_tree_view_set_rules_hint(view
, FALSE
);
319 column
= gtk_tree_view_column_new();
320 gtk_tree_view_append_column(view
, column
);
321 gtk_tree_view_column_set_title(column
, _("Options"));
323 renderer
= gtk_cell_renderer_toggle_new();
324 gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column
),
326 gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column
),
328 "active", COL_BTNACT
,
329 "inconsistent", COL_BTNINC
,
330 "visible", COL_BTNVIS
,
331 "radio", COL_BTNRAD
, NULL
);
332 renderer
= gtk_cell_renderer_text_new();
333 gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column
),
335 gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column
),
341 sel
= gtk_tree_view_get_selection(view
);
342 gtk_tree_selection_set_mode(sel
, GTK_SELECTION_SINGLE
);
343 gtk_widget_realize(tree1_w
);
346 static void renderer_edited(GtkCellRendererText
* cell
,
347 const gchar
* path_string
,
348 const gchar
* new_text
, gpointer user_data
);
349 static void renderer_toggled(GtkCellRendererToggle
* cellrenderertoggle
,
350 gchar
* arg1
, gpointer user_data
);
352 void init_right_tree(void)
354 GtkTreeView
*view
= GTK_TREE_VIEW(tree2_w
);
355 GtkCellRenderer
*renderer
;
356 GtkTreeSelection
*sel
;
357 GtkTreeViewColumn
*column
;
360 gtk_tree_view_set_model(view
, model2
);
361 gtk_tree_view_set_headers_visible(view
, TRUE
);
362 gtk_tree_view_set_rules_hint(view
, FALSE
);
364 column
= gtk_tree_view_column_new();
365 gtk_tree_view_append_column(view
, column
);
366 gtk_tree_view_column_set_title(column
, _("Options"));
368 renderer
= gtk_cell_renderer_pixbuf_new();
369 gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column
),
371 gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column
),
373 "pixbuf", COL_PIXBUF
,
374 "visible", COL_PIXVIS
, NULL
);
375 renderer
= gtk_cell_renderer_toggle_new();
376 gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column
),
378 gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column
),
380 "active", COL_BTNACT
,
381 "inconsistent", COL_BTNINC
,
382 "visible", COL_BTNVIS
,
383 "radio", COL_BTNRAD
, NULL
);
384 /*g_signal_connect(G_OBJECT(renderer), "toggled",
385 G_CALLBACK(renderer_toggled), NULL); */
386 renderer
= gtk_cell_renderer_text_new();
387 gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column
),
389 gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column
),
395 renderer
= gtk_cell_renderer_text_new();
396 gtk_tree_view_insert_column_with_attributes(view
, -1,
401 renderer
= gtk_cell_renderer_text_new();
402 gtk_tree_view_insert_column_with_attributes(view
, -1,
407 renderer
= gtk_cell_renderer_text_new();
408 gtk_tree_view_insert_column_with_attributes(view
, -1,
413 renderer
= gtk_cell_renderer_text_new();
414 gtk_tree_view_insert_column_with_attributes(view
, -1,
419 renderer
= gtk_cell_renderer_text_new();
420 gtk_tree_view_insert_column_with_attributes(view
, -1,
421 _("Value"), renderer
,
427 g_signal_connect(G_OBJECT(renderer
), "edited",
428 G_CALLBACK(renderer_edited
), NULL
);
430 column
= gtk_tree_view_get_column(view
, COL_NAME
);
431 gtk_tree_view_column_set_visible(column
, show_name
);
432 column
= gtk_tree_view_get_column(view
, COL_NO
);
433 gtk_tree_view_column_set_visible(column
, show_range
);
434 column
= gtk_tree_view_get_column(view
, COL_MOD
);
435 gtk_tree_view_column_set_visible(column
, show_range
);
436 column
= gtk_tree_view_get_column(view
, COL_YES
);
437 gtk_tree_view_column_set_visible(column
, show_range
);
438 column
= gtk_tree_view_get_column(view
, COL_VALUE
);
439 gtk_tree_view_column_set_visible(column
, show_value
);
442 for (i
= 0; i
< COL_VALUE
; i
++) {
443 column
= gtk_tree_view_get_column(view
, i
);
444 gtk_tree_view_column_set_resizable(column
, TRUE
);
448 sel
= gtk_tree_view_get_selection(view
);
449 gtk_tree_selection_set_mode(sel
, GTK_SELECTION_SINGLE
);
453 /* Utility Functions */
456 static void text_insert_help(struct menu
*menu
)
458 GtkTextBuffer
*buffer
;
459 GtkTextIter start
, end
;
460 const char *prompt
= menu_get_prompt(menu
);
464 help
= _(menu_get_help(menu
));
466 if (menu
->sym
&& menu
->sym
->name
)
467 name
= g_strdup_printf(_(menu
->sym
->name
));
471 buffer
= gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w
));
472 gtk_text_buffer_get_bounds(buffer
, &start
, &end
);
473 gtk_text_buffer_delete(buffer
, &start
, &end
);
474 gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_w
), 15);
476 gtk_text_buffer_get_end_iter(buffer
, &end
);
477 gtk_text_buffer_insert_with_tags(buffer
, &end
, prompt
, -1, tag1
,
479 gtk_text_buffer_insert_at_cursor(buffer
, " ", 1);
480 gtk_text_buffer_get_end_iter(buffer
, &end
);
481 gtk_text_buffer_insert_with_tags(buffer
, &end
, name
, -1, tag1
,
483 gtk_text_buffer_insert_at_cursor(buffer
, "\n\n", 2);
484 gtk_text_buffer_get_end_iter(buffer
, &end
);
485 gtk_text_buffer_insert_with_tags(buffer
, &end
, help
, -1, tag2
,
490 static void text_insert_msg(const char *title
, const char *message
)
492 GtkTextBuffer
*buffer
;
493 GtkTextIter start
, end
;
494 const char *msg
= message
;
496 buffer
= gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w
));
497 gtk_text_buffer_get_bounds(buffer
, &start
, &end
);
498 gtk_text_buffer_delete(buffer
, &start
, &end
);
499 gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_w
), 15);
501 gtk_text_buffer_get_end_iter(buffer
, &end
);
502 gtk_text_buffer_insert_with_tags(buffer
, &end
, title
, -1, tag1
,
504 gtk_text_buffer_insert_at_cursor(buffer
, "\n\n", 2);
505 gtk_text_buffer_get_end_iter(buffer
, &end
);
506 gtk_text_buffer_insert_with_tags(buffer
, &end
, msg
, -1, tag2
,
511 /* Main Windows Callbacks */
513 void on_save_activate(GtkMenuItem
* menuitem
, gpointer user_data
);
514 gboolean
on_window1_delete_event(GtkWidget
* widget
, GdkEvent
* event
,
517 GtkWidget
*dialog
, *label
;
520 if (!conf_get_changed())
523 dialog
= gtk_dialog_new_with_buttons(_("Warning !"),
524 GTK_WINDOW(main_wnd
),
527 GTK_DIALOG_DESTROY_WITH_PARENT
),
533 GTK_RESPONSE_CANCEL
, NULL
);
534 gtk_dialog_set_default_response(GTK_DIALOG(dialog
),
535 GTK_RESPONSE_CANCEL
);
537 label
= gtk_label_new(_("\nSave configuration ?\n"));
538 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog
)->vbox
), label
);
539 gtk_widget_show(label
);
541 result
= gtk_dialog_run(GTK_DIALOG(dialog
));
543 case GTK_RESPONSE_YES
:
544 on_save_activate(NULL
, NULL
);
546 case GTK_RESPONSE_NO
:
548 case GTK_RESPONSE_CANCEL
:
549 case GTK_RESPONSE_DELETE_EVENT
:
551 gtk_widget_destroy(dialog
);
559 void on_window1_destroy(GtkObject
* object
, gpointer user_data
)
566 on_window1_size_request(GtkWidget
* widget
,
567 GtkRequisition
* requisition
, gpointer user_data
)
572 if (widget
->window
== NULL
)
573 gtk_window_get_default_size(GTK_WINDOW(main_wnd
), &w
, &h
);
575 gdk_window_get_size(widget
->window
, &w
, &h
);
581 gtk_paned_set_position(GTK_PANED(vpaned
), 2 * h
/ 3);
585 /* Menu & Toolbar Callbacks */
589 load_filename(GtkFileSelection
* file_selector
, gpointer user_data
)
593 fn
= gtk_file_selection_get_filename(GTK_FILE_SELECTION
597 text_insert_msg(_("Error"), _("Unable to load configuration !"));
599 display_tree(&rootmenu
);
602 void on_load1_activate(GtkMenuItem
* menuitem
, gpointer user_data
)
606 fs
= gtk_file_selection_new(_("Load file..."));
607 g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs
)->ok_button
),
609 G_CALLBACK(load_filename
), (gpointer
) fs
);
610 g_signal_connect_swapped(GTK_OBJECT
611 (GTK_FILE_SELECTION(fs
)->ok_button
),
612 "clicked", G_CALLBACK(gtk_widget_destroy
),
614 g_signal_connect_swapped(GTK_OBJECT
615 (GTK_FILE_SELECTION(fs
)->cancel_button
),
616 "clicked", G_CALLBACK(gtk_widget_destroy
),
622 void on_save_activate(GtkMenuItem
* menuitem
, gpointer user_data
)
624 if (conf_write(NULL
))
625 text_insert_msg(_("Error"), _("Unable to save configuration !"));
630 store_filename(GtkFileSelection
* file_selector
, gpointer user_data
)
634 fn
= gtk_file_selection_get_filename(GTK_FILE_SELECTION
638 text_insert_msg(_("Error"), _("Unable to save configuration !"));
640 gtk_widget_destroy(GTK_WIDGET(user_data
));
643 void on_save_as1_activate(GtkMenuItem
* menuitem
, gpointer user_data
)
647 fs
= gtk_file_selection_new(_("Save file as..."));
648 g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs
)->ok_button
),
650 G_CALLBACK(store_filename
), (gpointer
) fs
);
651 g_signal_connect_swapped(GTK_OBJECT
652 (GTK_FILE_SELECTION(fs
)->ok_button
),
653 "clicked", G_CALLBACK(gtk_widget_destroy
),
655 g_signal_connect_swapped(GTK_OBJECT
656 (GTK_FILE_SELECTION(fs
)->cancel_button
),
657 "clicked", G_CALLBACK(gtk_widget_destroy
),
663 void on_quit1_activate(GtkMenuItem
* menuitem
, gpointer user_data
)
665 if (!on_window1_delete_event(NULL
, NULL
, NULL
))
666 gtk_widget_destroy(GTK_WIDGET(main_wnd
));
670 void on_show_name1_activate(GtkMenuItem
* menuitem
, gpointer user_data
)
672 GtkTreeViewColumn
*col
;
674 show_name
= GTK_CHECK_MENU_ITEM(menuitem
)->active
;
675 col
= gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w
), COL_NAME
);
677 gtk_tree_view_column_set_visible(col
, show_name
);
681 void on_show_range1_activate(GtkMenuItem
* menuitem
, gpointer user_data
)
683 GtkTreeViewColumn
*col
;
685 show_range
= GTK_CHECK_MENU_ITEM(menuitem
)->active
;
686 col
= gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w
), COL_NO
);
688 gtk_tree_view_column_set_visible(col
, show_range
);
689 col
= gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w
), COL_MOD
);
691 gtk_tree_view_column_set_visible(col
, show_range
);
692 col
= gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w
), COL_YES
);
694 gtk_tree_view_column_set_visible(col
, show_range
);
699 void on_show_data1_activate(GtkMenuItem
* menuitem
, gpointer user_data
)
701 GtkTreeViewColumn
*col
;
703 show_value
= GTK_CHECK_MENU_ITEM(menuitem
)->active
;
704 col
= gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w
), COL_VALUE
);
706 gtk_tree_view_column_set_visible(col
, show_value
);
711 on_show_all_options1_activate(GtkMenuItem
* menuitem
, gpointer user_data
)
713 show_all
= GTK_CHECK_MENU_ITEM(menuitem
)->active
;
715 gtk_tree_store_clear(tree2
);
716 display_tree(&rootmenu
); // instead of update_tree to speed-up
721 on_show_debug_info1_activate(GtkMenuItem
* menuitem
, gpointer user_data
)
723 show_debug
= GTK_CHECK_MENU_ITEM(menuitem
)->active
;
724 update_tree(&rootmenu
, NULL
);
728 void on_introduction1_activate(GtkMenuItem
* menuitem
, gpointer user_data
)
731 const gchar
*intro_text
= _(
732 "Welcome to gkc, the GTK+ graphical kernel configuration tool\n"
734 "For each option, a blank box indicates the feature is disabled, a\n"
735 "check indicates it is enabled, and a dot indicates that it is to\n"
736 "be compiled as a module. Clicking on the box will cycle through the three states.\n"
738 "If you do not see an option (e.g., a device driver) that you\n"
739 "believe should be present, try turning on Show All Options\n"
740 "under the Options menu.\n"
741 "Although there is no cross reference yet to help you figure out\n"
742 "what other options must be enabled to support the option you\n"
743 "are interested in, you can still view the help of a grayed-out\n"
746 "Toggling Show Debug Info under the Options menu will show \n"
747 "the dependencies, which you can then match by examining other options.");
749 dialog
= gtk_message_dialog_new(GTK_WINDOW(main_wnd
),
750 GTK_DIALOG_DESTROY_WITH_PARENT
,
752 GTK_BUTTONS_CLOSE
, intro_text
);
753 g_signal_connect_swapped(GTK_OBJECT(dialog
), "response",
754 G_CALLBACK(gtk_widget_destroy
),
756 gtk_widget_show_all(dialog
);
760 void on_about1_activate(GtkMenuItem
* menuitem
, gpointer user_data
)
763 const gchar
*about_text
=
764 _("gkc is copyright (c) 2002 Romain Lievin <roms@lpg.ticalc.org>.\n"
765 "Based on the source code from Roman Zippel.\n");
767 dialog
= gtk_message_dialog_new(GTK_WINDOW(main_wnd
),
768 GTK_DIALOG_DESTROY_WITH_PARENT
,
770 GTK_BUTTONS_CLOSE
, about_text
);
771 g_signal_connect_swapped(GTK_OBJECT(dialog
), "response",
772 G_CALLBACK(gtk_widget_destroy
),
774 gtk_widget_show_all(dialog
);
778 void on_license1_activate(GtkMenuItem
* menuitem
, gpointer user_data
)
781 const gchar
*license_text
=
782 _("gkc is released under the terms of the GNU GPL v2.\n"
783 "For more information, please see the source code or\n"
784 "visit http://www.fsf.org/licenses/licenses.html\n");
786 dialog
= gtk_message_dialog_new(GTK_WINDOW(main_wnd
),
787 GTK_DIALOG_DESTROY_WITH_PARENT
,
789 GTK_BUTTONS_CLOSE
, license_text
);
790 g_signal_connect_swapped(GTK_OBJECT(dialog
), "response",
791 G_CALLBACK(gtk_widget_destroy
),
793 gtk_widget_show_all(dialog
);
797 void on_back_clicked(GtkButton
* button
, gpointer user_data
)
799 enum prop_type ptype
;
801 current
= current
->parent
;
802 ptype
= current
->prompt
? current
->prompt
->type
: P_UNKNOWN
;
804 current
= current
->parent
;
807 if (current
== &rootmenu
)
808 gtk_widget_set_sensitive(back_btn
, FALSE
);
812 void on_load_clicked(GtkButton
* button
, gpointer user_data
)
814 on_load1_activate(NULL
, user_data
);
818 void on_single_clicked(GtkButton
* button
, gpointer user_data
)
820 view_mode
= SINGLE_VIEW
;
821 gtk_paned_set_position(GTK_PANED(hpaned
), 0);
822 gtk_widget_hide(tree1_w
);
828 void on_split_clicked(GtkButton
* button
, gpointer user_data
)
831 view_mode
= SPLIT_VIEW
;
832 gtk_widget_show(tree1_w
);
833 gtk_window_get_default_size(GTK_WINDOW(main_wnd
), &w
, &h
);
834 gtk_paned_set_position(GTK_PANED(hpaned
), w
/ 2);
836 gtk_tree_store_clear(tree2
);
839 /* Disable back btn, like in full mode. */
840 gtk_widget_set_sensitive(back_btn
, FALSE
);
844 void on_full_clicked(GtkButton
* button
, gpointer user_data
)
846 view_mode
= FULL_VIEW
;
847 gtk_paned_set_position(GTK_PANED(hpaned
), 0);
848 gtk_widget_hide(tree1_w
);
850 gtk_tree_store_clear(tree2
);
851 display_tree(&rootmenu
);
852 gtk_widget_set_sensitive(back_btn
, FALSE
);
856 void on_collapse_clicked(GtkButton
* button
, gpointer user_data
)
858 gtk_tree_view_collapse_all(GTK_TREE_VIEW(tree2_w
));
862 void on_expand_clicked(GtkButton
* button
, gpointer user_data
)
864 gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w
));
868 /* CTree Callbacks */
870 /* Change hex/int/string value in the cell */
871 static void renderer_edited(GtkCellRendererText
* cell
,
872 const gchar
* path_string
,
873 const gchar
* new_text
, gpointer user_data
)
875 GtkTreePath
*path
= gtk_tree_path_new_from_string(path_string
);
877 const char *old_def
, *new_def
;
881 if (!gtk_tree_model_get_iter(model2
, &iter
, path
))
884 gtk_tree_model_get(model2
, &iter
, COL_MENU
, &menu
, -1);
887 gtk_tree_model_get(model2
, &iter
, COL_VALUE
, &old_def
, -1);
890 sym_set_string_value(sym
, new_def
);
892 update_tree(&rootmenu
, NULL
);
894 gtk_tree_path_free(path
);
897 /* Change the value of a symbol and update the tree */
898 static void change_sym_value(struct menu
*menu
, gint col
)
900 struct symbol
*sym
= menu
->sym
;
901 tristate oldval
, newval
;
908 else if (col
== COL_MOD
)
910 else if (col
== COL_YES
)
915 switch (sym_get_type(sym
)) {
918 oldval
= sym_get_tristate_value(sym
);
919 if (!sym_tristate_within_range(sym
, newval
))
921 sym_set_tristate_value(sym
, newval
);
922 if (view_mode
== FULL_VIEW
)
923 update_tree(&rootmenu
, NULL
);
924 else if (view_mode
== SPLIT_VIEW
) {
925 update_tree(browsed
, NULL
);
928 else if (view_mode
== SINGLE_VIEW
)
929 display_tree_part(); //fixme: keep exp/coll
939 static void toggle_sym_value(struct menu
*menu
)
944 sym_toggle_tristate_value(menu
->sym
);
945 if (view_mode
== FULL_VIEW
)
946 update_tree(&rootmenu
, NULL
);
947 else if (view_mode
== SPLIT_VIEW
) {
948 update_tree(browsed
, NULL
);
951 else if (view_mode
== SINGLE_VIEW
)
952 display_tree_part(); //fixme: keep exp/coll
955 static void renderer_toggled(GtkCellRendererToggle
* cell
,
956 gchar
* path_string
, gpointer user_data
)
958 GtkTreePath
*path
, *sel_path
= NULL
;
959 GtkTreeIter iter
, sel_iter
;
960 GtkTreeSelection
*sel
;
963 path
= gtk_tree_path_new_from_string(path_string
);
964 if (!gtk_tree_model_get_iter(model2
, &iter
, path
))
967 sel
= gtk_tree_view_get_selection(GTK_TREE_VIEW(tree2_w
));
968 if (gtk_tree_selection_get_selected(sel
, NULL
, &sel_iter
))
969 sel_path
= gtk_tree_model_get_path(model2
, &sel_iter
);
972 if (gtk_tree_path_compare(path
, sel_path
))
975 gtk_tree_model_get(model2
, &iter
, COL_MENU
, &menu
, -1);
976 toggle_sym_value(menu
);
979 gtk_tree_path_free(sel_path
);
981 gtk_tree_path_free(path
);
984 static gint
column2index(GtkTreeViewColumn
* column
)
988 for (i
= 0; i
< COL_NUMBER
; i
++) {
989 GtkTreeViewColumn
*col
;
991 col
= gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w
), i
);
1000 /* User click: update choice (full) or goes down (single) */
1002 on_treeview2_button_press_event(GtkWidget
* widget
,
1003 GdkEventButton
* event
, gpointer user_data
)
1005 GtkTreeView
*view
= GTK_TREE_VIEW(widget
);
1007 GtkTreeViewColumn
*column
;
1012 #if GTK_CHECK_VERSION(2,1,4) // bug in ctree with earlier version of GTK
1013 gint tx
= (gint
) event
->x
;
1014 gint ty
= (gint
) event
->y
;
1017 gtk_tree_view_get_path_at_pos(view
, tx
, ty
, &path
, &column
, &cx
,
1020 gtk_tree_view_get_cursor(view
, &path
, &column
);
1025 if (!gtk_tree_model_get_iter(model2
, &iter
, path
))
1027 gtk_tree_model_get(model2
, &iter
, COL_MENU
, &menu
, -1);
1029 col
= column2index(column
);
1030 if (event
->type
== GDK_2BUTTON_PRESS
) {
1031 enum prop_type ptype
;
1032 ptype
= menu
->prompt
? menu
->prompt
->type
: P_UNKNOWN
;
1034 if (ptype
== P_MENU
&& view_mode
!= FULL_VIEW
&& col
== COL_OPTION
) {
1035 // goes down into menu
1037 display_tree_part();
1038 gtk_widget_set_sensitive(back_btn
, TRUE
);
1039 } else if ((col
== COL_OPTION
)) {
1040 toggle_sym_value(menu
);
1041 gtk_tree_view_expand_row(view
, path
, TRUE
);
1044 if (col
== COL_VALUE
) {
1045 toggle_sym_value(menu
);
1046 gtk_tree_view_expand_row(view
, path
, TRUE
);
1047 } else if (col
== COL_NO
|| col
== COL_MOD
1048 || col
== COL_YES
) {
1049 change_sym_value(menu
, col
);
1050 gtk_tree_view_expand_row(view
, path
, TRUE
);
1057 /* Key pressed: update choice */
1059 on_treeview2_key_press_event(GtkWidget
* widget
,
1060 GdkEventKey
* event
, gpointer user_data
)
1062 GtkTreeView
*view
= GTK_TREE_VIEW(widget
);
1064 GtkTreeViewColumn
*column
;
1069 gtk_tree_view_get_cursor(view
, &path
, &column
);
1073 if (event
->keyval
== GDK_space
) {
1074 if (gtk_tree_view_row_expanded(view
, path
))
1075 gtk_tree_view_collapse_row(view
, path
);
1077 gtk_tree_view_expand_row(view
, path
, FALSE
);
1080 if (event
->keyval
== GDK_KP_Enter
) {
1082 if (widget
== tree1_w
)
1085 gtk_tree_model_get_iter(model2
, &iter
, path
);
1086 gtk_tree_model_get(model2
, &iter
, COL_MENU
, &menu
, -1);
1088 if (!strcasecmp(event
->string
, "n"))
1090 else if (!strcasecmp(event
->string
, "m"))
1092 else if (!strcasecmp(event
->string
, "y"))
1096 change_sym_value(menu
, col
);
1102 /* Row selection changed: update help */
1104 on_treeview2_cursor_changed(GtkTreeView
* treeview
, gpointer user_data
)
1106 GtkTreeSelection
*selection
;
1110 selection
= gtk_tree_view_get_selection(treeview
);
1111 if (gtk_tree_selection_get_selected(selection
, &model2
, &iter
)) {
1112 gtk_tree_model_get(model2
, &iter
, COL_MENU
, &menu
, -1);
1113 text_insert_help(menu
);
1118 /* User click: display sub-tree in the right frame. */
1120 on_treeview1_button_press_event(GtkWidget
* widget
,
1121 GdkEventButton
* event
, gpointer user_data
)
1123 GtkTreeView
*view
= GTK_TREE_VIEW(widget
);
1125 GtkTreeViewColumn
*column
;
1129 gint tx
= (gint
) event
->x
;
1130 gint ty
= (gint
) event
->y
;
1133 gtk_tree_view_get_path_at_pos(view
, tx
, ty
, &path
, &column
, &cx
,
1138 gtk_tree_model_get_iter(model1
, &iter
, path
);
1139 gtk_tree_model_get(model1
, &iter
, COL_MENU
, &menu
, -1);
1141 if (event
->type
== GDK_2BUTTON_PRESS
) {
1142 toggle_sym_value(menu
);
1144 display_tree_part();
1147 display_tree_part();
1150 gtk_widget_realize(tree2_w
);
1151 gtk_tree_view_set_cursor(view
, path
, NULL
, FALSE
);
1152 gtk_widget_grab_focus(tree2_w
);
1158 /* Fill a row of strings */
1159 static gchar
**fill_row(struct menu
*menu
)
1161 static gchar
*row
[COL_NUMBER
];
1162 struct symbol
*sym
= menu
->sym
;
1166 enum prop_type ptype
;
1169 for (i
= COL_OPTION
; i
<= COL_COLOR
; i
++)
1171 bzero(row
, sizeof(row
));
1174 g_strdup_printf("%s %s", menu_get_prompt(menu
),
1175 sym
&& sym_has_value(sym
) ? "(NEW)" : "");
1177 if (show_all
&& !menu_is_visible(menu
))
1178 row
[COL_COLOR
] = g_strdup("DarkGray");
1180 row
[COL_COLOR
] = g_strdup("Black");
1182 ptype
= menu
->prompt
? menu
->prompt
->type
: P_UNKNOWN
;
1185 row
[COL_PIXBUF
] = (gchar
*) xpm_menu
;
1186 if (view_mode
== SINGLE_VIEW
)
1187 row
[COL_PIXVIS
] = GINT_TO_POINTER(TRUE
);
1188 row
[COL_BTNVIS
] = GINT_TO_POINTER(FALSE
);
1191 row
[COL_PIXBUF
] = (gchar
*) xpm_void
;
1192 row
[COL_PIXVIS
] = GINT_TO_POINTER(FALSE
);
1193 row
[COL_BTNVIS
] = GINT_TO_POINTER(FALSE
);
1196 row
[COL_PIXBUF
] = (gchar
*) xpm_void
;
1197 row
[COL_PIXVIS
] = GINT_TO_POINTER(FALSE
);
1198 row
[COL_BTNVIS
] = GINT_TO_POINTER(TRUE
);
1204 row
[COL_NAME
] = g_strdup(sym
->name
);
1206 sym_calc_value(sym
);
1207 sym
->flags
&= ~SYMBOL_CHANGED
;
1209 if (sym_is_choice(sym
)) { // parse childs for getting final value
1211 struct symbol
*def_sym
= sym_get_choice_value(sym
);
1212 struct menu
*def_menu
= NULL
;
1214 row
[COL_BTNVIS
] = GINT_TO_POINTER(FALSE
);
1216 for (child
= menu
->list
; child
; child
= child
->next
) {
1217 if (menu_is_visible(child
)
1218 && child
->sym
== def_sym
)
1224 g_strdup(menu_get_prompt(def_menu
));
1226 if (sym
->flags
& SYMBOL_CHOICEVAL
)
1227 row
[COL_BTNRAD
] = GINT_TO_POINTER(TRUE
);
1229 stype
= sym_get_type(sym
);
1232 if (GPOINTER_TO_INT(row
[COL_PIXVIS
]) == FALSE
)
1233 row
[COL_BTNVIS
] = GINT_TO_POINTER(TRUE
);
1234 if (sym_is_choice(sym
))
1237 val
= sym_get_tristate_value(sym
);
1240 row
[COL_NO
] = g_strdup("N");
1241 row
[COL_VALUE
] = g_strdup("N");
1242 row
[COL_BTNACT
] = GINT_TO_POINTER(FALSE
);
1243 row
[COL_BTNINC
] = GINT_TO_POINTER(FALSE
);
1246 row
[COL_MOD
] = g_strdup("M");
1247 row
[COL_VALUE
] = g_strdup("M");
1248 row
[COL_BTNINC
] = GINT_TO_POINTER(TRUE
);
1251 row
[COL_YES
] = g_strdup("Y");
1252 row
[COL_VALUE
] = g_strdup("Y");
1253 row
[COL_BTNACT
] = GINT_TO_POINTER(TRUE
);
1254 row
[COL_BTNINC
] = GINT_TO_POINTER(FALSE
);
1258 if (val
!= no
&& sym_tristate_within_range(sym
, no
))
1259 row
[COL_NO
] = g_strdup("_");
1260 if (val
!= mod
&& sym_tristate_within_range(sym
, mod
))
1261 row
[COL_MOD
] = g_strdup("_");
1262 if (val
!= yes
&& sym_tristate_within_range(sym
, yes
))
1263 row
[COL_YES
] = g_strdup("_");
1268 def
= sym_get_string_value(sym
);
1269 row
[COL_VALUE
] = g_strdup(def
);
1270 row
[COL_EDIT
] = GINT_TO_POINTER(TRUE
);
1271 row
[COL_BTNVIS
] = GINT_TO_POINTER(FALSE
);
1279 /* Set the node content with a row of strings */
1280 static void set_node(GtkTreeIter
* node
, struct menu
*menu
, gchar
** row
)
1286 pix
= gdk_pixbuf_new_from_xpm_data((const char **)
1289 gdk_color_parse(row
[COL_COLOR
], &color
);
1290 gdk_colormap_alloc_colors(gdk_colormap_get_system(), &color
, 1,
1291 FALSE
, FALSE
, &success
);
1293 gtk_tree_store_set(tree
, node
,
1294 COL_OPTION
, row
[COL_OPTION
],
1295 COL_NAME
, row
[COL_NAME
],
1296 COL_NO
, row
[COL_NO
],
1297 COL_MOD
, row
[COL_MOD
],
1298 COL_YES
, row
[COL_YES
],
1299 COL_VALUE
, row
[COL_VALUE
],
1300 COL_MENU
, (gpointer
) menu
,
1302 COL_EDIT
, GPOINTER_TO_INT(row
[COL_EDIT
]),
1304 COL_PIXVIS
, GPOINTER_TO_INT(row
[COL_PIXVIS
]),
1305 COL_BTNVIS
, GPOINTER_TO_INT(row
[COL_BTNVIS
]),
1306 COL_BTNACT
, GPOINTER_TO_INT(row
[COL_BTNACT
]),
1307 COL_BTNINC
, GPOINTER_TO_INT(row
[COL_BTNINC
]),
1308 COL_BTNRAD
, GPOINTER_TO_INT(row
[COL_BTNRAD
]),
1311 g_object_unref(pix
);
1315 /* Add a node to the tree */
1316 static void place_node(struct menu
*menu
, char **row
)
1318 GtkTreeIter
*parent
= parents
[indent
- 1];
1319 GtkTreeIter
*node
= parents
[indent
];
1321 gtk_tree_store_append(tree
, node
, parent
);
1322 set_node(node
, menu
, row
);
1326 /* Find a node in the GTK+ tree */
1327 static GtkTreeIter found
;
1330 * Find a menu in the GtkTree starting at parent.
1332 GtkTreeIter
*gtktree_iter_find_node(GtkTreeIter
* parent
,
1333 struct menu
*tofind
)
1336 GtkTreeIter
*child
= &iter
;
1340 valid
= gtk_tree_model_iter_children(model2
, child
, parent
);
1344 gtk_tree_model_get(model2
, child
, 6, &menu
, -1);
1346 if (menu
== tofind
) {
1347 memcpy(&found
, child
, sizeof(GtkTreeIter
));
1351 ret
= gtktree_iter_find_node(child
, tofind
);
1355 valid
= gtk_tree_model_iter_next(model2
, child
);
1363 * Update the tree by adding/removing entries
1364 * Does not change other nodes
1366 static void update_tree(struct menu
*src
, GtkTreeIter
* dst
)
1368 struct menu
*child1
;
1369 GtkTreeIter iter
, tmp
;
1370 GtkTreeIter
*child2
= &iter
;
1372 GtkTreeIter
*sibling
;
1374 struct property
*prop
;
1375 struct menu
*menu1
, *menu2
;
1377 if (src
== &rootmenu
)
1380 valid
= gtk_tree_model_iter_children(model2
, child2
, dst
);
1381 for (child1
= src
->list
; child1
; child1
= child1
->next
) {
1383 prop
= child1
->prompt
;
1389 gtk_tree_model_get(model2
, child2
, COL_MENU
,
1392 menu2
= NULL
; // force adding of a first child
1395 printf("%*c%s | %s\n", indent
, ' ',
1396 menu1
? menu_get_prompt(menu1
) : "nil",
1397 menu2
? menu_get_prompt(menu2
) : "nil");
1400 if (!menu_is_visible(child1
) && !show_all
) { // remove node
1401 if (gtktree_iter_find_node(dst
, menu1
) != NULL
) {
1402 memcpy(&tmp
, child2
, sizeof(GtkTreeIter
));
1403 valid
= gtk_tree_model_iter_next(model2
,
1405 gtk_tree_store_remove(tree2
, &tmp
);
1407 return; // next parent
1409 goto reparse
; // next child
1414 if (menu1
!= menu2
) {
1415 if (gtktree_iter_find_node(dst
, menu1
) == NULL
) { // add node
1416 if (!valid
&& !menu2
)
1420 gtk_tree_store_insert_before(tree2
,
1423 set_node(child2
, menu1
, fill_row(menu1
));
1426 } else { // remove node
1427 memcpy(&tmp
, child2
, sizeof(GtkTreeIter
));
1428 valid
= gtk_tree_model_iter_next(model2
,
1430 gtk_tree_store_remove(tree2
, &tmp
);
1432 return; // next parent
1434 goto reparse
; // next child
1436 } else if (sym
&& (sym
->flags
& SYMBOL_CHANGED
)) {
1437 set_node(child2
, menu1
, fill_row(menu1
));
1441 update_tree(child1
, child2
);
1444 valid
= gtk_tree_model_iter_next(model2
, child2
);
1449 /* Display the whole tree (single/split/full view) */
1450 static void display_tree(struct menu
*menu
)
1453 struct property
*prop
;
1455 enum prop_type ptype
;
1457 if (menu
== &rootmenu
) {
1459 current
= &rootmenu
;
1462 for (child
= menu
->list
; child
; child
= child
->next
) {
1463 prop
= child
->prompt
;
1465 ptype
= prop
? prop
->type
: P_UNKNOWN
;
1468 sym
->flags
&= ~SYMBOL_CHANGED
;
1470 if ((view_mode
== SPLIT_VIEW
)
1471 && !(child
->flags
& MENU_ROOT
) && (tree
== tree1
))
1474 if ((view_mode
== SPLIT_VIEW
) && (child
->flags
& MENU_ROOT
)
1478 if (menu_is_visible(child
) || show_all
)
1479 place_node(child
, fill_row(child
));
1481 printf("%*c%s: ", indent
, ' ', menu_get_prompt(child
));
1482 printf("%s", child
->flags
& MENU_ROOT
? "rootmenu | " : "");
1483 dbg_print_ptype(ptype
);
1486 dbg_print_stype(sym
->type
);
1488 dbg_print_flags(sym
->flags
);
1493 if ((view_mode
!= FULL_VIEW
) && (ptype
== P_MENU
)
1497 if (((menu != &rootmenu) && !(menu->flags & MENU_ROOT))
1498 || (view_mode == FULL_VIEW)
1499 || (view_mode == SPLIT_VIEW))*/
1500 if (((view_mode
== SINGLE_VIEW
) && (menu
->flags
& MENU_ROOT
))
1501 || (view_mode
== FULL_VIEW
)
1502 || (view_mode
== SPLIT_VIEW
)) {
1504 display_tree(child
);
1510 /* Display a part of the tree starting at current node (single/split view) */
1511 static void display_tree_part(void)
1514 gtk_tree_store_clear(tree2
);
1515 if (view_mode
== SINGLE_VIEW
)
1516 display_tree(current
);
1517 else if (view_mode
== SPLIT_VIEW
)
1518 display_tree(browsed
);
1519 gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w
));
1522 /* Display the list in the left frame (split view) */
1523 static void display_list(void)
1526 gtk_tree_store_clear(tree1
);
1529 display_tree(&rootmenu
);
1530 gtk_tree_view_expand_all(GTK_TREE_VIEW(tree1_w
));
1534 void fixup_rootmenu(struct menu
*menu
)
1537 static int menu_cnt
= 0;
1539 menu
->flags
|= MENU_ROOT
;
1540 for (child
= menu
->list
; child
; child
= child
->next
) {
1541 if (child
->prompt
&& child
->prompt
->type
== P_MENU
) {
1543 fixup_rootmenu(child
);
1545 } else if (!menu_cnt
)
1546 fixup_rootmenu(child
);
1552 int main(int ac
, char *av
[])
1558 #ifndef LKC_DIRECT_LINK
1562 bindtextdomain(PACKAGE
, LOCALEDIR
);
1563 bind_textdomain_codeset(PACKAGE
, "UTF-8");
1564 textdomain(PACKAGE
);
1571 //add_pixmap_directory (PACKAGE_DATA_DIR "/" PACKAGE "/pixmaps");
1572 //add_pixmap_directory (PACKAGE_SOURCE_DIR "/pixmaps");
1574 /* Determine GUI path */
1575 env
= getenv(SRCTREE
);
1577 glade_file
= g_strconcat(env
, "/scripts/kconfig/gconf.glade", NULL
);
1578 else if (av
[0][0] == '/')
1579 glade_file
= g_strconcat(av
[0], ".glade", NULL
);
1581 glade_file
= g_strconcat(g_get_current_dir(), "/", av
[0], ".glade", NULL
);
1583 /* Load the interface and connect signals */
1584 init_main_window(glade_file
);
1590 if (ac
> 1 && av
[1][0] == '-') {
1597 printf("%s <config>\n", av
[0]);
1605 fixup_rootmenu(&rootmenu
);
1608 switch (view_mode
) {
1610 display_tree_part();
1616 display_tree(&rootmenu
);
1625 static void conf_changed(void)
1627 bool changed
= conf_get_changed();
1628 gtk_widget_set_sensitive(save_btn
, changed
);
1629 gtk_widget_set_sensitive(save_menu_item
, changed
);