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 static gboolean config_changed = FALSE;
43 static char nohelp_text[] =
44 "Sorry, no help available for this option yet.\n";
46 GtkWidget *main_wnd = NULL;
47 GtkWidget *tree1_w = NULL; // left frame
48 GtkWidget *tree2_w = NULL; // right frame
49 GtkWidget *text_w = NULL;
50 GtkWidget *hpaned = NULL;
51 GtkWidget *vpaned = NULL;
52 GtkWidget *back_btn = NULL;
54 GtkTextTag *tag1, *tag2;
57 GtkTreeStore *tree1, *tree2, *tree;
58 GtkTreeModel *model1, *model2;
59 static GtkTreeIter *parents[256];
62 static struct menu *current; // current node for SINGLE view
63 static struct menu *browsed; // browsed node for SPLIT view
66 COL_OPTION, COL_NAME, COL_NO, COL_MOD, COL_YES, COL_VALUE,
67 COL_MENU, COL_COLOR, COL_EDIT, COL_PIXBUF,
68 COL_PIXVIS, COL_BTNVIS, COL_BTNACT, COL_BTNINC, COL_BTNRAD,
72 static void display_list(void);
73 static void display_tree(struct menu *menu);
74 static void display_tree_part(void);
75 static void update_tree(struct menu *src, GtkTreeIter * dst);
76 static void set_node(GtkTreeIter * node, struct menu *menu, gchar ** row);
77 static gchar **fill_row(struct menu *menu);
80 /* Helping/Debugging Functions */
83 const char *dbg_print_stype(int val)
90 strcpy(buf, "unknown");
92 strcpy(buf, "boolean");
93 if (val == S_TRISTATE)
94 strcpy(buf, "tristate");
100 strcpy(buf, "string");
102 strcpy(buf, "other");
111 const char *dbg_print_flags(int val)
113 static char buf[256];
117 if (val & SYMBOL_YES)
119 if (val & SYMBOL_MOD)
123 if (val & SYMBOL_CONST)
124 strcat(buf, "const/");
125 if (val & SYMBOL_CHECK)
126 strcat(buf, "check/");
127 if (val & SYMBOL_CHOICE)
128 strcat(buf, "choice/");
129 if (val & SYMBOL_CHOICEVAL)
130 strcat(buf, "choiceval/");
131 if (val & SYMBOL_PRINTED)
132 strcat(buf, "printed/");
133 if (val & SYMBOL_VALID)
134 strcat(buf, "valid/");
135 if (val & SYMBOL_OPTIONAL)
136 strcat(buf, "optional/");
137 if (val & SYMBOL_WRITE)
138 strcat(buf, "write/");
139 if (val & SYMBOL_CHANGED)
140 strcat(buf, "changed/");
141 if (val & SYMBOL_NEW)
143 if (val & SYMBOL_AUTO)
144 strcat(buf, "auto/");
146 buf[strlen(buf) - 1] = '\0';
154 const char *dbg_print_ptype(int val)
156 static char buf[256];
160 if (val == P_UNKNOWN)
161 strcpy(buf, "unknown");
163 strcpy(buf, "prompt");
164 if (val == P_COMMENT)
165 strcpy(buf, "comment");
168 if (val == P_DEFAULT)
169 strcpy(buf, "default");
171 strcpy(buf, "choice");
181 /* Main Window Initialization */
184 void init_main_window(const gchar * glade_file)
188 GtkTextBuffer *txtbuf;
192 xml = glade_xml_new(glade_file, "window1", NULL);
194 g_error("GUI loading failed !\n");
195 glade_xml_signal_autoconnect(xml);
197 main_wnd = glade_xml_get_widget(xml, "window1");
198 hpaned = glade_xml_get_widget(xml, "hpaned1");
199 vpaned = glade_xml_get_widget(xml, "vpaned1");
200 tree1_w = glade_xml_get_widget(xml, "treeview1");
201 tree2_w = glade_xml_get_widget(xml, "treeview2");
202 text_w = glade_xml_get_widget(xml, "textview3");
204 back_btn = glade_xml_get_widget(xml, "button1");
205 gtk_widget_set_sensitive(back_btn, FALSE);
207 widget = glade_xml_get_widget(xml, "show_name1");
208 gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget,
211 widget = glade_xml_get_widget(xml, "show_range1");
212 gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget,
215 widget = glade_xml_get_widget(xml, "show_data1");
216 gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget,
219 style = gtk_widget_get_style(main_wnd);
220 widget = glade_xml_get_widget(xml, "toolbar1");
224 widget = glade_xml_get_widget(xml, "button4");
225 gtk_button_clicked(GTK_BUTTON(widget));
228 widget = glade_xml_get_widget(xml, "button5");
229 gtk_button_clicked(GTK_BUTTON(widget));
232 widget = glade_xml_get_widget(xml, "button6");
233 gtk_button_clicked(GTK_BUTTON(widget));
237 txtbuf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w));
238 tag1 = gtk_text_buffer_create_tag(txtbuf, "mytag1",
240 "weight", PANGO_WEIGHT_BOLD,
242 tag2 = gtk_text_buffer_create_tag(txtbuf, "mytag2",
243 /*"style", PANGO_STYLE_OBLIQUE, */
246 sprintf(title, "Linux Kernel v%s Configuration",
247 getenv("KERNELRELEASE"));
248 gtk_window_set_title(GTK_WINDOW(main_wnd), title);
250 gtk_widget_show(main_wnd);
253 void init_tree_model(void)
257 tree = tree2 = gtk_tree_store_new(COL_NUMBER,
258 G_TYPE_STRING, G_TYPE_STRING,
259 G_TYPE_STRING, G_TYPE_STRING,
260 G_TYPE_STRING, G_TYPE_STRING,
261 G_TYPE_POINTER, GDK_TYPE_COLOR,
262 G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF,
263 G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
264 G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
266 model2 = GTK_TREE_MODEL(tree2);
268 for (parents[0] = NULL, i = 1; i < 256; i++)
269 parents[i] = (GtkTreeIter *) g_malloc(sizeof(GtkTreeIter));
271 tree1 = gtk_tree_store_new(COL_NUMBER,
272 G_TYPE_STRING, G_TYPE_STRING,
273 G_TYPE_STRING, G_TYPE_STRING,
274 G_TYPE_STRING, G_TYPE_STRING,
275 G_TYPE_POINTER, GDK_TYPE_COLOR,
276 G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF,
277 G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
278 G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
280 model1 = GTK_TREE_MODEL(tree1);
283 void init_left_tree(void)
285 GtkTreeView *view = GTK_TREE_VIEW(tree1_w);
286 GtkCellRenderer *renderer;
287 GtkTreeSelection *sel;
288 GtkTreeViewColumn *column;
290 gtk_tree_view_set_model(view, model1);
291 gtk_tree_view_set_headers_visible(view, TRUE);
292 gtk_tree_view_set_rules_hint(view, FALSE);
294 column = gtk_tree_view_column_new();
295 gtk_tree_view_append_column(view, column);
296 gtk_tree_view_column_set_title(column, "Options");
298 renderer = gtk_cell_renderer_toggle_new();
299 gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
301 gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
303 "active", COL_BTNACT,
304 "inconsistent", COL_BTNINC,
305 "visible", COL_BTNVIS,
306 "radio", COL_BTNRAD, NULL);
307 renderer = gtk_cell_renderer_text_new();
308 gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
310 gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
316 sel = gtk_tree_view_get_selection(view);
317 gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
318 gtk_widget_realize(tree1_w);
321 static void renderer_edited(GtkCellRendererText * cell,
322 const gchar * path_string,
323 const gchar * new_text, gpointer user_data);
324 static void renderer_toggled(GtkCellRendererToggle * cellrenderertoggle,
325 gchar * arg1, gpointer user_data);
327 void init_right_tree(void)
329 GtkTreeView *view = GTK_TREE_VIEW(tree2_w);
330 GtkCellRenderer *renderer;
331 GtkTreeSelection *sel;
332 GtkTreeViewColumn *column;
335 gtk_tree_view_set_model(view, model2);
336 gtk_tree_view_set_headers_visible(view, TRUE);
337 gtk_tree_view_set_rules_hint(view, FALSE);
339 column = gtk_tree_view_column_new();
340 gtk_tree_view_append_column(view, column);
341 gtk_tree_view_column_set_title(column, "Options");
343 renderer = gtk_cell_renderer_pixbuf_new();
344 gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
346 gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
348 "pixbuf", COL_PIXBUF,
349 "visible", COL_PIXVIS, NULL);
350 renderer = gtk_cell_renderer_toggle_new();
351 gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
353 gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
355 "active", COL_BTNACT,
356 "inconsistent", COL_BTNINC,
357 "visible", COL_BTNVIS,
358 "radio", COL_BTNRAD, NULL);
359 /*g_signal_connect(G_OBJECT(renderer), "toggled",
360 G_CALLBACK(renderer_toggled), NULL); */
361 renderer = gtk_cell_renderer_text_new();
362 gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
364 gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
370 renderer = gtk_cell_renderer_text_new();
371 gtk_tree_view_insert_column_with_attributes(view, -1,
376 renderer = gtk_cell_renderer_text_new();
377 gtk_tree_view_insert_column_with_attributes(view, -1,
382 renderer = gtk_cell_renderer_text_new();
383 gtk_tree_view_insert_column_with_attributes(view, -1,
388 renderer = gtk_cell_renderer_text_new();
389 gtk_tree_view_insert_column_with_attributes(view, -1,
394 renderer = gtk_cell_renderer_text_new();
395 gtk_tree_view_insert_column_with_attributes(view, -1,
402 g_signal_connect(G_OBJECT(renderer), "edited",
403 G_CALLBACK(renderer_edited), NULL);
405 column = gtk_tree_view_get_column(view, COL_NAME);
406 gtk_tree_view_column_set_visible(column, show_name);
407 column = gtk_tree_view_get_column(view, COL_NO);
408 gtk_tree_view_column_set_visible(column, show_range);
409 column = gtk_tree_view_get_column(view, COL_MOD);
410 gtk_tree_view_column_set_visible(column, show_range);
411 column = gtk_tree_view_get_column(view, COL_YES);
412 gtk_tree_view_column_set_visible(column, show_range);
413 column = gtk_tree_view_get_column(view, COL_VALUE);
414 gtk_tree_view_column_set_visible(column, show_value);
417 for (i = 0; i < COL_VALUE; i++) {
418 column = gtk_tree_view_get_column(view, i);
419 gtk_tree_view_column_set_resizable(column, TRUE);
423 sel = gtk_tree_view_get_selection(view);
424 gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
428 /* Utility Functions */
431 static void text_insert_help(struct menu *menu)
433 GtkTextBuffer *buffer;
434 GtkTextIter start, end;
435 const char *prompt = menu_get_prompt(menu);
437 const char *help = nohelp_text;
441 else if (menu->sym->help)
442 help = menu->sym->help;
444 if (menu->sym && menu->sym->name)
445 name = g_strdup_printf(menu->sym->name);
449 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w));
450 gtk_text_buffer_get_bounds(buffer, &start, &end);
451 gtk_text_buffer_delete(buffer, &start, &end);
452 gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_w), 15);
454 gtk_text_buffer_get_end_iter(buffer, &end);
455 gtk_text_buffer_insert_with_tags(buffer, &end, prompt, -1, tag1,
457 gtk_text_buffer_insert_at_cursor(buffer, " ", 1);
458 gtk_text_buffer_get_end_iter(buffer, &end);
459 gtk_text_buffer_insert_with_tags(buffer, &end, name, -1, tag1,
461 gtk_text_buffer_insert_at_cursor(buffer, "\n\n", 2);
462 gtk_text_buffer_get_end_iter(buffer, &end);
463 gtk_text_buffer_insert_with_tags(buffer, &end, help, -1, tag2,
468 static void text_insert_msg(const char *title, const char *message)
470 GtkTextBuffer *buffer;
471 GtkTextIter start, end;
472 const char *msg = message;
474 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w));
475 gtk_text_buffer_get_bounds(buffer, &start, &end);
476 gtk_text_buffer_delete(buffer, &start, &end);
477 gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_w), 15);
479 gtk_text_buffer_get_end_iter(buffer, &end);
480 gtk_text_buffer_insert_with_tags(buffer, &end, title, -1, tag1,
482 gtk_text_buffer_insert_at_cursor(buffer, "\n\n", 2);
483 gtk_text_buffer_get_end_iter(buffer, &end);
484 gtk_text_buffer_insert_with_tags(buffer, &end, msg, -1, tag2,
489 /* Main Windows Callbacks */
491 void on_save1_activate(GtkMenuItem * menuitem, gpointer user_data);
492 gboolean on_window1_delete_event(GtkWidget * widget, GdkEvent * event,
495 GtkWidget *dialog, *label;
498 if (config_changed == FALSE)
501 dialog = gtk_dialog_new_with_buttons("Warning !",
502 GTK_WINDOW(main_wnd),
505 GTK_DIALOG_DESTROY_WITH_PARENT),
511 GTK_RESPONSE_CANCEL, NULL);
512 gtk_dialog_set_default_response(GTK_DIALOG(dialog),
513 GTK_RESPONSE_CANCEL);
515 label = gtk_label_new("\nSave configuration ?\n");
516 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), label);
517 gtk_widget_show(label);
519 result = gtk_dialog_run(GTK_DIALOG(dialog));
521 case GTK_RESPONSE_YES:
522 on_save1_activate(NULL, NULL);
524 case GTK_RESPONSE_NO:
526 case GTK_RESPONSE_CANCEL:
527 case GTK_RESPONSE_DELETE_EVENT:
529 gtk_widget_destroy(dialog);
537 void on_window1_destroy(GtkObject * object, gpointer user_data)
544 on_window1_size_request(GtkWidget * widget,
545 GtkRequisition * requisition, gpointer user_data)
550 if (widget->window == NULL)
551 gtk_window_get_default_size(GTK_WINDOW(main_wnd), &w, &h);
553 gdk_window_get_size(widget->window, &w, &h);
559 gtk_paned_set_position(GTK_PANED(vpaned), 2 * h / 3);
563 /* Menu & Toolbar Callbacks */
567 load_filename(GtkFileSelection * file_selector, gpointer user_data)
571 fn = gtk_file_selection_get_filename(GTK_FILE_SELECTION
575 text_insert_msg("Error", "Unable to load configuration !");
577 display_tree(&rootmenu);
580 void on_load1_activate(GtkMenuItem * menuitem, gpointer user_data)
584 fs = gtk_file_selection_new("Load file...");
585 g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs)->ok_button),
587 G_CALLBACK(load_filename), (gpointer) fs);
588 g_signal_connect_swapped(GTK_OBJECT
589 (GTK_FILE_SELECTION(fs)->ok_button),
590 "clicked", G_CALLBACK(gtk_widget_destroy),
592 g_signal_connect_swapped(GTK_OBJECT
593 (GTK_FILE_SELECTION(fs)->cancel_button),
594 "clicked", G_CALLBACK(gtk_widget_destroy),
600 void on_save1_activate(GtkMenuItem * menuitem, gpointer user_data)
602 if (conf_write(NULL))
603 text_insert_msg("Error", "Unable to save configuration !");
605 config_changed = FALSE;
610 store_filename(GtkFileSelection * file_selector, gpointer user_data)
614 fn = gtk_file_selection_get_filename(GTK_FILE_SELECTION
618 text_insert_msg("Error", "Unable to save configuration !");
620 gtk_widget_destroy(GTK_WIDGET(user_data));
623 void on_save_as1_activate(GtkMenuItem * menuitem, gpointer user_data)
627 fs = gtk_file_selection_new("Save file as...");
628 g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs)->ok_button),
630 G_CALLBACK(store_filename), (gpointer) fs);
631 g_signal_connect_swapped(GTK_OBJECT
632 (GTK_FILE_SELECTION(fs)->ok_button),
633 "clicked", G_CALLBACK(gtk_widget_destroy),
635 g_signal_connect_swapped(GTK_OBJECT
636 (GTK_FILE_SELECTION(fs)->cancel_button),
637 "clicked", G_CALLBACK(gtk_widget_destroy),
643 void on_quit1_activate(GtkMenuItem * menuitem, gpointer user_data)
645 if (!on_window1_delete_event(NULL, NULL, NULL))
646 gtk_widget_destroy(GTK_WIDGET(main_wnd));
650 void on_show_name1_activate(GtkMenuItem * menuitem, gpointer user_data)
652 GtkTreeViewColumn *col;
654 show_name = GTK_CHECK_MENU_ITEM(menuitem)->active;
655 col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_NAME);
657 gtk_tree_view_column_set_visible(col, show_name);
661 void on_show_range1_activate(GtkMenuItem * menuitem, gpointer user_data)
663 GtkTreeViewColumn *col;
665 show_range = GTK_CHECK_MENU_ITEM(menuitem)->active;
666 col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_NO);
668 gtk_tree_view_column_set_visible(col, show_range);
669 col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_MOD);
671 gtk_tree_view_column_set_visible(col, show_range);
672 col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_YES);
674 gtk_tree_view_column_set_visible(col, show_range);
679 void on_show_data1_activate(GtkMenuItem * menuitem, gpointer user_data)
681 GtkTreeViewColumn *col;
683 show_value = GTK_CHECK_MENU_ITEM(menuitem)->active;
684 col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_VALUE);
686 gtk_tree_view_column_set_visible(col, show_value);
691 on_show_all_options1_activate(GtkMenuItem * menuitem, gpointer user_data)
693 show_all = GTK_CHECK_MENU_ITEM(menuitem)->active;
695 gtk_tree_store_clear(tree2);
696 display_tree(&rootmenu); // instead of update_tree to speed-up
701 on_show_debug_info1_activate(GtkMenuItem * menuitem, gpointer user_data)
703 show_debug = GTK_CHECK_MENU_ITEM(menuitem)->active;
704 update_tree(&rootmenu, NULL);
708 void on_introduction1_activate(GtkMenuItem * menuitem, gpointer user_data)
711 const gchar *intro_text =
712 "Welcome to gkc, the GTK+ graphical kernel configuration tool\n"
714 "For each option, a blank box indicates the feature is disabled, a\n"
715 "check indicates it is enabled, and a dot indicates that it is to\n"
716 "be compiled as a module. Clicking on the box will cycle through the three states.\n"
718 "If you do not see an option (e.g., a device driver) that you\n"
719 "believe should be present, try turning on Show All Options\n"
720 "under the Options menu.\n"
721 "Although there is no cross reference yet to help you figure out\n"
722 "what other options must be enabled to support the option you\n"
723 "are interested in, you can still view the help of a grayed-out\n"
726 "Toggling Show Debug Info under the Options menu will show \n"
727 "the dependencies, which you can then match by examining other options.";
729 dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
730 GTK_DIALOG_DESTROY_WITH_PARENT,
732 GTK_BUTTONS_CLOSE, intro_text);
733 g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
734 G_CALLBACK(gtk_widget_destroy),
736 gtk_widget_show_all(dialog);
740 void on_about1_activate(GtkMenuItem * menuitem, gpointer user_data)
743 const gchar *about_text =
744 "gkc is copyright (c) 2002 Romain Lievin <roms@lpg.ticalc.org>.\n"
745 "Based on the source code from Roman Zippel.\n";
747 dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
748 GTK_DIALOG_DESTROY_WITH_PARENT,
750 GTK_BUTTONS_CLOSE, about_text);
751 g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
752 G_CALLBACK(gtk_widget_destroy),
754 gtk_widget_show_all(dialog);
758 void on_license1_activate(GtkMenuItem * menuitem, gpointer user_data)
761 const gchar *license_text =
762 "gkc is released under the terms of the GNU GPL v2.\n"
763 "For more information, please see the source code or\n"
764 "visit http://www.fsf.org/licenses/licenses.html\n";
766 dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
767 GTK_DIALOG_DESTROY_WITH_PARENT,
769 GTK_BUTTONS_CLOSE, license_text);
770 g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
771 G_CALLBACK(gtk_widget_destroy),
773 gtk_widget_show_all(dialog);
777 void on_back_pressed(GtkButton * button, gpointer user_data)
779 enum prop_type ptype;
781 current = current->parent;
782 ptype = current->prompt ? current->prompt->type : P_UNKNOWN;
784 current = current->parent;
787 if (current == &rootmenu)
788 gtk_widget_set_sensitive(back_btn, FALSE);
792 void on_load_pressed(GtkButton * button, gpointer user_data)
794 on_load1_activate(NULL, user_data);
798 void on_save_pressed(GtkButton * button, gpointer user_data)
800 on_save1_activate(NULL, user_data);
804 void on_single_clicked(GtkButton * button, gpointer user_data)
806 view_mode = SINGLE_VIEW;
807 gtk_paned_set_position(GTK_PANED(hpaned), 0);
808 gtk_widget_hide(tree1_w);
814 void on_split_clicked(GtkButton * button, gpointer user_data)
817 view_mode = SPLIT_VIEW;
818 gtk_widget_show(tree1_w);
819 gtk_window_get_default_size(GTK_WINDOW(main_wnd), &w, &h);
820 gtk_paned_set_position(GTK_PANED(hpaned), w / 2);
822 gtk_tree_store_clear(tree2);
827 void on_full_clicked(GtkButton * button, gpointer user_data)
829 view_mode = FULL_VIEW;
830 gtk_paned_set_position(GTK_PANED(hpaned), 0);
831 gtk_widget_hide(tree1_w);
833 gtk_tree_store_clear(tree2);
834 display_tree(&rootmenu);
835 gtk_widget_set_sensitive(back_btn, FALSE);
839 void on_collapse_pressed(GtkButton * button, gpointer user_data)
841 gtk_tree_view_collapse_all(GTK_TREE_VIEW(tree2_w));
845 void on_expand_pressed(GtkButton * button, gpointer user_data)
847 gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w));
851 /* CTree Callbacks */
853 /* Change hex/int/string value in the cell */
854 static void renderer_edited(GtkCellRendererText * cell,
855 const gchar * path_string,
856 const gchar * new_text, gpointer user_data)
858 GtkTreePath *path = gtk_tree_path_new_from_string(path_string);
860 const char *old_def, *new_def;
864 if (!gtk_tree_model_get_iter(model2, &iter, path))
867 gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
870 gtk_tree_model_get(model2, &iter, COL_VALUE, &old_def, -1);
873 sym_set_string_value(sym, new_def);
875 config_changed = TRUE;
876 update_tree(&rootmenu, NULL);
878 gtk_tree_path_free(path);
881 /* Change the value of a symbol and update the tree */
882 static void change_sym_value(struct menu *menu, gint col)
884 struct symbol *sym = menu->sym;
885 tristate oldval, newval;
892 else if (col == COL_MOD)
894 else if (col == COL_YES)
899 switch (sym_get_type(sym)) {
902 oldval = sym_get_tristate_value(sym);
903 if (!sym_tristate_within_range(sym, newval))
905 sym_set_tristate_value(sym, newval);
906 config_changed = TRUE;
907 if (view_mode == FULL_VIEW)
908 update_tree(&rootmenu, NULL);
909 else if (view_mode == SPLIT_VIEW) {
910 update_tree(browsed, NULL);
913 else if (view_mode == SINGLE_VIEW)
914 display_tree_part(); //fixme: keep exp/coll
924 static void toggle_sym_value(struct menu *menu)
929 sym_toggle_tristate_value(menu->sym);
930 if (view_mode == FULL_VIEW)
931 update_tree(&rootmenu, NULL);
932 else if (view_mode == SPLIT_VIEW) {
933 update_tree(browsed, NULL);
936 else if (view_mode == SINGLE_VIEW)
937 display_tree_part(); //fixme: keep exp/coll
940 static void renderer_toggled(GtkCellRendererToggle * cell,
941 gchar * path_string, gpointer user_data)
943 GtkTreePath *path, *sel_path = NULL;
944 GtkTreeIter iter, sel_iter;
945 GtkTreeSelection *sel;
948 path = gtk_tree_path_new_from_string(path_string);
949 if (!gtk_tree_model_get_iter(model2, &iter, path))
952 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree2_w));
953 if (gtk_tree_selection_get_selected(sel, NULL, &sel_iter))
954 sel_path = gtk_tree_model_get_path(model2, &sel_iter);
957 if (gtk_tree_path_compare(path, sel_path))
960 gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
961 toggle_sym_value(menu);
964 gtk_tree_path_free(sel_path);
966 gtk_tree_path_free(path);
969 static gint column2index(GtkTreeViewColumn * column)
973 for (i = 0; i < COL_NUMBER; i++) {
974 GtkTreeViewColumn *col;
976 col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), i);
985 /* User click: update choice (full) or goes down (single) */
987 on_treeview2_button_press_event(GtkWidget * widget,
988 GdkEventButton * event, gpointer user_data)
990 GtkTreeView *view = GTK_TREE_VIEW(widget);
992 GtkTreeViewColumn *column;
997 #if GTK_CHECK_VERSION(2,1,4) // bug in ctree with earlier version of GTK
998 gint tx = (gint) event->x;
999 gint ty = (gint) event->y;
1002 gtk_tree_view_get_path_at_pos(view, tx, ty, &path, &column, &cx,
1005 gtk_tree_view_get_cursor(view, &path, &column);
1010 if (!gtk_tree_model_get_iter(model2, &iter, path))
1012 gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
1014 col = column2index(column);
1015 if (event->type == GDK_2BUTTON_PRESS) {
1016 enum prop_type ptype;
1017 ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
1019 if (ptype == P_MENU && view_mode != FULL_VIEW && col == COL_OPTION) {
1020 // goes down into menu
1022 display_tree_part();
1023 gtk_widget_set_sensitive(back_btn, TRUE);
1024 } else if ((col == COL_OPTION)) {
1025 toggle_sym_value(menu);
1026 gtk_tree_view_expand_row(view, path, TRUE);
1029 if (col == COL_VALUE) {
1030 toggle_sym_value(menu);
1031 gtk_tree_view_expand_row(view, path, TRUE);
1032 } else if (col == COL_NO || col == COL_MOD
1033 || col == COL_YES) {
1034 change_sym_value(menu, col);
1035 gtk_tree_view_expand_row(view, path, TRUE);
1042 /* Key pressed: update choice */
1044 on_treeview2_key_press_event(GtkWidget * widget,
1045 GdkEventKey * event, gpointer user_data)
1047 GtkTreeView *view = GTK_TREE_VIEW(widget);
1049 GtkTreeViewColumn *column;
1054 gtk_tree_view_get_cursor(view, &path, &column);
1058 if (event->keyval == GDK_space) {
1059 if (gtk_tree_view_row_expanded(view, path))
1060 gtk_tree_view_collapse_row(view, path);
1062 gtk_tree_view_expand_row(view, path, FALSE);
1065 if (event->keyval == GDK_KP_Enter) {
1067 if (widget == tree1_w)
1070 gtk_tree_model_get_iter(model2, &iter, path);
1071 gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
1073 if (!strcasecmp(event->string, "n"))
1075 else if (!strcasecmp(event->string, "m"))
1077 else if (!strcasecmp(event->string, "y"))
1081 change_sym_value(menu, col);
1087 /* Row selection changed: update help */
1089 on_treeview2_cursor_changed(GtkTreeView * treeview, gpointer user_data)
1091 GtkTreeSelection *selection;
1095 selection = gtk_tree_view_get_selection(treeview);
1096 if (gtk_tree_selection_get_selected(selection, &model2, &iter)) {
1097 gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
1098 text_insert_help(menu);
1103 /* User click: display sub-tree in the right frame. */
1105 on_treeview1_button_press_event(GtkWidget * widget,
1106 GdkEventButton * event, gpointer user_data)
1108 GtkTreeView *view = GTK_TREE_VIEW(widget);
1110 GtkTreeViewColumn *column;
1114 gint tx = (gint) event->x;
1115 gint ty = (gint) event->y;
1118 gtk_tree_view_get_path_at_pos(view, tx, ty, &path, &column, &cx,
1123 gtk_tree_model_get_iter(model1, &iter, path);
1124 gtk_tree_model_get(model1, &iter, COL_MENU, &menu, -1);
1126 if (event->type == GDK_2BUTTON_PRESS) {
1127 toggle_sym_value(menu);
1129 display_tree_part();
1132 display_tree_part();
1135 gtk_widget_realize(tree2_w);
1136 gtk_tree_view_set_cursor(view, path, NULL, FALSE);
1137 gtk_widget_grab_focus(tree2_w);
1143 /* Conf management */
1146 /* Fill a row of strings */
1147 static gchar **fill_row(struct menu *menu)
1149 static gchar *row[COL_NUMBER];
1150 struct symbol *sym = menu->sym;
1154 enum prop_type ptype;
1157 for (i = COL_OPTION; i <= COL_COLOR; i++)
1159 bzero(row, sizeof(row));
1162 g_strdup_printf("%s %s", menu_get_prompt(menu),
1164 flags & SYMBOL_NEW ? "(NEW)" : "") :
1167 if (show_all && !menu_is_visible(menu))
1168 row[COL_COLOR] = g_strdup("DarkGray");
1170 row[COL_COLOR] = g_strdup("Black");
1172 ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
1175 row[COL_PIXBUF] = (gchar *) xpm_menu;
1176 if (view_mode == SINGLE_VIEW)
1177 row[COL_PIXVIS] = GINT_TO_POINTER(TRUE);
1178 row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
1181 row[COL_PIXBUF] = (gchar *) xpm_void;
1182 row[COL_PIXVIS] = GINT_TO_POINTER(FALSE);
1183 row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
1186 row[COL_PIXBUF] = (gchar *) xpm_void;
1187 row[COL_PIXVIS] = GINT_TO_POINTER(FALSE);
1188 row[COL_BTNVIS] = GINT_TO_POINTER(TRUE);
1194 row[COL_NAME] = g_strdup(sym->name);
1196 sym_calc_value(sym);
1197 sym->flags &= ~SYMBOL_CHANGED;
1199 if (sym_is_choice(sym)) { // parse childs for getting final value
1201 struct symbol *def_sym = sym_get_choice_value(sym);
1202 struct menu *def_menu = NULL;
1204 row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
1206 for (child = menu->list; child; child = child->next) {
1207 if (menu_is_visible(child)
1208 && child->sym == def_sym)
1214 g_strdup(menu_get_prompt(def_menu));
1216 if(sym->flags & SYMBOL_CHOICEVAL)
1217 row[COL_BTNRAD] = GINT_TO_POINTER(TRUE);
1219 stype = sym_get_type(sym);
1222 if(GPOINTER_TO_INT(row[COL_PIXVIS]) == FALSE)
1223 row[COL_BTNVIS] = GINT_TO_POINTER(TRUE);
1224 if (sym_is_choice(sym))
1227 val = sym_get_tristate_value(sym);
1230 row[COL_NO] = g_strdup("N");
1231 row[COL_VALUE] = g_strdup("N");
1232 row[COL_BTNACT] = GINT_TO_POINTER(FALSE);
1233 row[COL_BTNINC] = GINT_TO_POINTER(FALSE);
1236 row[COL_MOD] = g_strdup("M");
1237 row[COL_VALUE] = g_strdup("M");
1238 row[COL_BTNINC] = GINT_TO_POINTER(TRUE);
1241 row[COL_YES] = g_strdup("Y");
1242 row[COL_VALUE] = g_strdup("Y");
1243 row[COL_BTNACT] = GINT_TO_POINTER(TRUE);
1244 row[COL_BTNINC] = GINT_TO_POINTER(FALSE);
1248 if (val != no && sym_tristate_within_range(sym, no))
1249 row[COL_NO] = g_strdup("_");
1250 if (val != mod && sym_tristate_within_range(sym, mod))
1251 row[COL_MOD] = g_strdup("_");
1252 if (val != yes && sym_tristate_within_range(sym, yes))
1253 row[COL_YES] = g_strdup("_");
1258 def = sym_get_string_value(sym);
1259 row[COL_VALUE] = g_strdup(def);
1260 row[COL_EDIT] = GINT_TO_POINTER(TRUE);
1261 row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
1269 /* Set the node content with a row of strings */
1270 static void set_node(GtkTreeIter * node, struct menu *menu, gchar ** row)
1276 pix = gdk_pixbuf_new_from_xpm_data((const char **)
1279 gdk_color_parse(row[COL_COLOR], &color);
1280 gdk_colormap_alloc_colors(gdk_colormap_get_system(), &color, 1,
1281 FALSE, FALSE, &success);
1283 gtk_tree_store_set(tree, node,
1284 COL_OPTION, row[COL_OPTION],
1285 COL_NAME, row[COL_NAME],
1286 COL_NO, row[COL_NO],
1287 COL_MOD, row[COL_MOD],
1288 COL_YES, row[COL_YES],
1289 COL_VALUE, row[COL_VALUE],
1290 COL_MENU, (gpointer) menu,
1292 COL_EDIT, GPOINTER_TO_INT(row[COL_EDIT]),
1294 COL_PIXVIS, GPOINTER_TO_INT(row[COL_PIXVIS]),
1295 COL_BTNVIS, GPOINTER_TO_INT(row[COL_BTNVIS]),
1296 COL_BTNACT, GPOINTER_TO_INT(row[COL_BTNACT]),
1297 COL_BTNINC, GPOINTER_TO_INT(row[COL_BTNINC]),
1298 COL_BTNRAD, GPOINTER_TO_INT(row[COL_BTNRAD]),
1301 g_object_unref(pix);
1305 /* Add a node to the tree */
1306 static void place_node(struct menu *menu, char **row)
1308 GtkTreeIter *parent = parents[indent - 1];
1309 GtkTreeIter *node = parents[indent];
1311 gtk_tree_store_append(tree, node, parent);
1312 set_node(node, menu, row);
1316 /* Find a node in the GTK+ tree */
1317 static GtkTreeIter found;
1320 * Find a menu in the GtkTree starting at parent.
1322 GtkTreeIter *gtktree_iter_find_node(GtkTreeIter * parent,
1323 struct menu *tofind)
1326 GtkTreeIter *child = &iter;
1330 valid = gtk_tree_model_iter_children(model2, child, parent);
1334 gtk_tree_model_get(model2, child, 6, &menu, -1);
1336 if (menu == tofind) {
1337 memcpy(&found, child, sizeof(GtkTreeIter));
1341 ret = gtktree_iter_find_node(child, tofind);
1345 valid = gtk_tree_model_iter_next(model2, child);
1353 * Update the tree by adding/removing entries
1354 * Does not change other nodes
1356 static void update_tree(struct menu *src, GtkTreeIter * dst)
1358 struct menu *child1;
1359 GtkTreeIter iter, tmp;
1360 GtkTreeIter *child2 = &iter;
1362 GtkTreeIter *sibling;
1364 struct property *prop;
1365 struct menu *menu1, *menu2;
1367 if (src == &rootmenu)
1370 valid = gtk_tree_model_iter_children(model2, child2, dst);
1371 for (child1 = src->list; child1; child1 = child1->next) {
1373 prop = child1->prompt;
1379 gtk_tree_model_get(model2, child2, COL_MENU,
1382 menu2 = NULL; // force adding of a first child
1385 printf("%*c%s | %s\n", indent, ' ',
1386 menu1 ? menu_get_prompt(menu1) : "nil",
1387 menu2 ? menu_get_prompt(menu2) : "nil");
1390 if (!menu_is_visible(child1) && !show_all) { // remove node
1391 if (gtktree_iter_find_node(dst, menu1) != NULL) {
1392 memcpy(&tmp, child2, sizeof(GtkTreeIter));
1393 valid = gtk_tree_model_iter_next(model2,
1395 gtk_tree_store_remove(tree2, &tmp);
1397 return; // next parent
1399 goto reparse; // next child
1404 if (menu1 != menu2) {
1405 if (gtktree_iter_find_node(dst, menu1) == NULL) { // add node
1406 if (!valid && !menu2)
1410 gtk_tree_store_insert_before(tree2,
1413 set_node(child2, menu1, fill_row(menu1));
1416 } else { // remove node
1417 memcpy(&tmp, child2, sizeof(GtkTreeIter));
1418 valid = gtk_tree_model_iter_next(model2,
1420 gtk_tree_store_remove(tree2, &tmp);
1422 return; // next parent
1424 goto reparse; // next child
1426 } else if (sym && (sym->flags & SYMBOL_CHANGED)) {
1427 set_node(child2, menu1, fill_row(menu1));
1431 update_tree(child1, child2);
1434 valid = gtk_tree_model_iter_next(model2, child2);
1439 /* Display the whole tree (single/split/full view) */
1440 static void display_tree(struct menu *menu)
1443 struct property *prop;
1445 enum prop_type ptype;
1447 if (menu == &rootmenu) {
1449 current = &rootmenu;
1452 for (child = menu->list; child; child = child->next) {
1453 prop = child->prompt;
1455 ptype = prop ? prop->type : P_UNKNOWN;
1458 sym->flags &= ~SYMBOL_CHANGED;
1460 if ((view_mode == SPLIT_VIEW) && !(child->flags & MENU_ROOT) &&
1464 if ((view_mode == SPLIT_VIEW) && (child->flags & MENU_ROOT) &&
1468 if (menu_is_visible(child) || show_all)
1469 place_node(child, fill_row(child));
1471 printf("%*c%s: ", indent, ' ', menu_get_prompt(child));
1472 printf("%s", child->flags & MENU_ROOT ? "rootmenu | " : "");
1473 dbg_print_ptype(ptype);
1476 dbg_print_stype(sym->type);
1478 dbg_print_flags(sym->flags);
1483 if ((view_mode != FULL_VIEW) && (ptype == P_MENU)
1487 if (((menu != &rootmenu) && !(menu->flags & MENU_ROOT)) ||
1488 (view_mode == FULL_VIEW)
1489 || (view_mode == SPLIT_VIEW))*/
1490 if (((view_mode == SINGLE_VIEW) && (menu->flags & MENU_ROOT))
1491 || (view_mode == FULL_VIEW) || (view_mode == SPLIT_VIEW)) {
1493 display_tree(child);
1499 /* Display a part of the tree starting at current node (single/split view) */
1500 static void display_tree_part(void)
1503 gtk_tree_store_clear(tree2);
1504 if(view_mode == SINGLE_VIEW)
1505 display_tree(current);
1506 else if(view_mode == SPLIT_VIEW)
1507 display_tree(browsed);
1508 gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w));
1511 /* Display the list in the left frame (split view) */
1512 static void display_list(void)
1515 gtk_tree_store_clear(tree1);
1518 display_tree(&rootmenu);
1519 gtk_tree_view_expand_all(GTK_TREE_VIEW(tree1_w));
1523 void fixup_rootmenu(struct menu *menu)
1526 static int menu_cnt = 0;
1528 menu->flags |= MENU_ROOT;
1529 for (child = menu->list; child; child = child->next) {
1530 if (child->prompt && child->prompt->type == P_MENU) {
1532 fixup_rootmenu(child);
1534 } else if (!menu_cnt)
1535 fixup_rootmenu(child);
1543 int main(int ac, char *av[])
1549 #ifndef LKC_DIRECT_LINK
1558 //add_pixmap_directory (PACKAGE_DATA_DIR "/" PACKAGE "/pixmaps");
1559 //add_pixmap_directory (PACKAGE_SOURCE_DIR "/pixmaps");
1561 /* Determine GUI path */
1562 env = getenv(SRCTREE);
1564 glade_file = g_strconcat(env, "/scripts/kconfig/gconf.glade", NULL);
1565 else if (av[0][0] == '/')
1566 glade_file = g_strconcat(av[0], ".glade", NULL);
1568 glade_file = g_strconcat(g_get_current_dir(), "/", av[0], ".glade", NULL);
1570 /* Load the interface and connect signals */
1571 init_main_window(glade_file);
1577 if (ac > 1 && av[1][0] == '-') {
1584 printf("%s <config>\n", av[0]);
1592 fixup_rootmenu(&rootmenu);
1595 switch (view_mode) {
1597 display_tree_part();
1603 display_tree(&rootmenu);