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;
194 xml = glade_xml_new(glade_file, "window1", NULL);
196 g_error("GUI loading failed !\n");
197 glade_xml_signal_autoconnect(xml);
199 main_wnd = glade_xml_get_widget(xml, "window1");
200 hpaned = glade_xml_get_widget(xml, "hpaned1");
201 vpaned = glade_xml_get_widget(xml, "vpaned1");
202 tree1_w = glade_xml_get_widget(xml, "treeview1");
203 tree2_w = glade_xml_get_widget(xml, "treeview2");
204 text_w = glade_xml_get_widget(xml, "textview3");
206 back_btn = glade_xml_get_widget(xml, "button1");
207 gtk_widget_set_sensitive(back_btn, FALSE);
209 widget = glade_xml_get_widget(xml, "show_name1");
210 gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget,
213 widget = glade_xml_get_widget(xml, "show_range1");
214 gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget,
217 widget = glade_xml_get_widget(xml, "show_data1");
218 gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget,
221 style = gtk_widget_get_style(main_wnd);
222 widget = glade_xml_get_widget(xml, "toolbar1");
224 pixmap = gdk_pixmap_create_from_xpm_d(main_wnd->window, &mask,
225 &style->bg[GTK_STATE_NORMAL],
226 (gchar **) xpm_single_view);
227 gtk_image_set_from_pixmap(GTK_IMAGE
229 *) (g_list_nth(GTK_TOOLBAR(widget)->
234 gdk_pixmap_create_from_xpm_d(main_wnd->window, &mask,
235 &style->bg[GTK_STATE_NORMAL],
236 (gchar **) xpm_split_view);
237 gtk_image_set_from_pixmap(GTK_IMAGE
239 *) (g_list_nth(GTK_TOOLBAR(widget)->
244 gdk_pixmap_create_from_xpm_d(main_wnd->window, &mask,
245 &style->bg[GTK_STATE_NORMAL],
246 (gchar **) xpm_tree_view);
247 gtk_image_set_from_pixmap(GTK_IMAGE
249 *) (g_list_nth(GTK_TOOLBAR(widget)->
256 widget = glade_xml_get_widget(xml, "button4");
257 gtk_button_clicked(GTK_BUTTON(widget));
260 widget = glade_xml_get_widget(xml, "button5");
261 gtk_button_clicked(GTK_BUTTON(widget));
264 widget = glade_xml_get_widget(xml, "button6");
265 gtk_button_clicked(GTK_BUTTON(widget));
269 txtbuf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w));
270 tag1 = gtk_text_buffer_create_tag(txtbuf, "mytag1",
272 "weight", PANGO_WEIGHT_BOLD,
274 tag2 = gtk_text_buffer_create_tag(txtbuf, "mytag2",
275 /*"style", PANGO_STYLE_OBLIQUE, */
278 sprintf(title, "Linux Kernel v%s.%s.%s%s Configuration",
279 getenv("VERSION"), getenv("PATCHLEVEL"),
280 getenv("SUBLEVEL"), getenv("EXTRAVERSION"));
281 gtk_window_set_title(GTK_WINDOW(main_wnd), title);
283 gtk_widget_show(main_wnd);
286 void init_tree_model(void)
290 tree = tree2 = gtk_tree_store_new(COL_NUMBER,
291 G_TYPE_STRING, G_TYPE_STRING,
292 G_TYPE_STRING, G_TYPE_STRING,
293 G_TYPE_STRING, G_TYPE_STRING,
294 G_TYPE_POINTER, GDK_TYPE_COLOR,
295 G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF,
296 G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
297 G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
299 model2 = GTK_TREE_MODEL(tree2);
301 for (parents[0] = NULL, i = 1; i < 256; i++)
302 parents[i] = (GtkTreeIter *) g_malloc(sizeof(GtkTreeIter));
304 tree1 = gtk_tree_store_new(COL_NUMBER,
305 G_TYPE_STRING, G_TYPE_STRING,
306 G_TYPE_STRING, G_TYPE_STRING,
307 G_TYPE_STRING, G_TYPE_STRING,
308 G_TYPE_POINTER, GDK_TYPE_COLOR,
309 G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF,
310 G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
311 G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
313 model1 = GTK_TREE_MODEL(tree1);
316 void init_left_tree(void)
318 GtkTreeView *view = GTK_TREE_VIEW(tree1_w);
319 GtkCellRenderer *renderer;
320 GtkTreeSelection *sel;
321 GtkTreeViewColumn *column;
323 gtk_tree_view_set_model(view, model1);
324 gtk_tree_view_set_headers_visible(view, TRUE);
325 gtk_tree_view_set_rules_hint(view, FALSE);
327 column = gtk_tree_view_column_new();
328 gtk_tree_view_append_column(view, column);
329 gtk_tree_view_column_set_title(column, "Options");
331 renderer = gtk_cell_renderer_toggle_new();
332 gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
334 gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
336 "active", COL_BTNACT,
337 "inconsistent", COL_BTNINC,
338 "visible", COL_BTNVIS,
339 "radio", COL_BTNRAD, NULL);
340 renderer = gtk_cell_renderer_text_new();
341 gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
343 gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
349 sel = gtk_tree_view_get_selection(view);
350 gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
351 gtk_widget_realize(tree1_w);
354 static void renderer_edited(GtkCellRendererText * cell,
355 const gchar * path_string,
356 const gchar * new_text, gpointer user_data);
357 static void renderer_toggled(GtkCellRendererToggle * cellrenderertoggle,
358 gchar * arg1, gpointer user_data);
360 void init_right_tree(void)
362 GtkTreeView *view = GTK_TREE_VIEW(tree2_w);
363 GtkCellRenderer *renderer;
364 GtkTreeSelection *sel;
365 GtkTreeViewColumn *column;
368 gtk_tree_view_set_model(view, model2);
369 gtk_tree_view_set_headers_visible(view, TRUE);
370 gtk_tree_view_set_rules_hint(view, FALSE);
372 column = gtk_tree_view_column_new();
373 gtk_tree_view_append_column(view, column);
374 gtk_tree_view_column_set_title(column, "Options");
376 renderer = gtk_cell_renderer_pixbuf_new();
377 gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
379 gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
381 "pixbuf", COL_PIXBUF,
382 "visible", COL_PIXVIS, NULL);
383 renderer = gtk_cell_renderer_toggle_new();
384 gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
386 gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
388 "active", COL_BTNACT,
389 "inconsistent", COL_BTNINC,
390 "visible", COL_BTNVIS,
391 "radio", COL_BTNRAD, NULL);
392 /*g_signal_connect(G_OBJECT(renderer), "toggled",
393 G_CALLBACK(renderer_toggled), NULL); */
394 renderer = gtk_cell_renderer_text_new();
395 gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
397 gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
403 renderer = gtk_cell_renderer_text_new();
404 gtk_tree_view_insert_column_with_attributes(view, -1,
409 renderer = gtk_cell_renderer_text_new();
410 gtk_tree_view_insert_column_with_attributes(view, -1,
415 renderer = gtk_cell_renderer_text_new();
416 gtk_tree_view_insert_column_with_attributes(view, -1,
421 renderer = gtk_cell_renderer_text_new();
422 gtk_tree_view_insert_column_with_attributes(view, -1,
427 renderer = gtk_cell_renderer_text_new();
428 gtk_tree_view_insert_column_with_attributes(view, -1,
435 g_signal_connect(G_OBJECT(renderer), "edited",
436 G_CALLBACK(renderer_edited), NULL);
438 column = gtk_tree_view_get_column(view, COL_NAME);
439 gtk_tree_view_column_set_visible(column, show_name);
440 column = gtk_tree_view_get_column(view, COL_NO);
441 gtk_tree_view_column_set_visible(column, show_range);
442 column = gtk_tree_view_get_column(view, COL_MOD);
443 gtk_tree_view_column_set_visible(column, show_range);
444 column = gtk_tree_view_get_column(view, COL_YES);
445 gtk_tree_view_column_set_visible(column, show_range);
446 column = gtk_tree_view_get_column(view, COL_VALUE);
447 gtk_tree_view_column_set_visible(column, show_value);
450 for (i = 0; i < COL_VALUE; i++) {
451 column = gtk_tree_view_get_column(view, i);
452 gtk_tree_view_column_set_resizable(column, TRUE);
456 sel = gtk_tree_view_get_selection(view);
457 gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
461 /* Utility Functions */
464 static void text_insert_help(struct menu *menu)
466 GtkTextBuffer *buffer;
467 GtkTextIter start, end;
468 const char *prompt = menu_get_prompt(menu);
470 const char *help = nohelp_text;
474 else if (menu->sym->help)
475 help = menu->sym->help;
477 if (menu->sym && menu->sym->name)
478 name = g_strdup_printf(menu->sym->name);
482 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w));
483 gtk_text_buffer_get_bounds(buffer, &start, &end);
484 gtk_text_buffer_delete(buffer, &start, &end);
485 gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_w), 15);
487 gtk_text_buffer_get_end_iter(buffer, &end);
488 gtk_text_buffer_insert_with_tags(buffer, &end, prompt, -1, tag1,
490 gtk_text_buffer_insert_at_cursor(buffer, " ", 1);
491 gtk_text_buffer_get_end_iter(buffer, &end);
492 gtk_text_buffer_insert_with_tags(buffer, &end, name, -1, tag1,
494 gtk_text_buffer_insert_at_cursor(buffer, "\n\n", 2);
495 gtk_text_buffer_get_end_iter(buffer, &end);
496 gtk_text_buffer_insert_with_tags(buffer, &end, help, -1, tag2,
501 static void text_insert_msg(const char *title, const char *message)
503 GtkTextBuffer *buffer;
504 GtkTextIter start, end;
505 const char *msg = message;
507 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w));
508 gtk_text_buffer_get_bounds(buffer, &start, &end);
509 gtk_text_buffer_delete(buffer, &start, &end);
510 gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_w), 15);
512 gtk_text_buffer_get_end_iter(buffer, &end);
513 gtk_text_buffer_insert_with_tags(buffer, &end, title, -1, tag1,
515 gtk_text_buffer_insert_at_cursor(buffer, "\n\n", 2);
516 gtk_text_buffer_get_end_iter(buffer, &end);
517 gtk_text_buffer_insert_with_tags(buffer, &end, msg, -1, tag2,
522 /* Main Windows Callbacks */
524 void on_save1_activate(GtkMenuItem * menuitem, gpointer user_data);
525 gboolean on_window1_delete_event(GtkWidget * widget, GdkEvent * event,
528 GtkWidget *dialog, *label;
531 if (config_changed == FALSE)
534 dialog = gtk_dialog_new_with_buttons("Warning !",
535 GTK_WINDOW(main_wnd),
538 GTK_DIALOG_DESTROY_WITH_PARENT),
544 GTK_RESPONSE_CANCEL, NULL);
545 gtk_dialog_set_default_response(GTK_DIALOG(dialog),
546 GTK_RESPONSE_CANCEL);
548 label = gtk_label_new("\nSave configuration ?\n");
549 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), label);
550 gtk_widget_show(label);
552 result = gtk_dialog_run(GTK_DIALOG(dialog));
554 case GTK_RESPONSE_YES:
555 on_save1_activate(NULL, NULL);
557 case GTK_RESPONSE_NO:
559 case GTK_RESPONSE_CANCEL:
560 case GTK_RESPONSE_DELETE_EVENT:
562 gtk_widget_destroy(dialog);
570 void on_window1_destroy(GtkObject * object, gpointer user_data)
577 on_window1_size_request(GtkWidget * widget,
578 GtkRequisition * requisition, gpointer user_data)
583 if (widget->window == NULL)
584 gtk_window_get_default_size(GTK_WINDOW(main_wnd), &w, &h);
586 gdk_window_get_size(widget->window, &w, &h);
592 gtk_paned_set_position(GTK_PANED(vpaned), 2 * h / 3);
596 /* Menu & Toolbar Callbacks */
600 load_filename(GtkFileSelection * file_selector, gpointer user_data)
604 fn = gtk_file_selection_get_filename(GTK_FILE_SELECTION
608 text_insert_msg("Error", "Unable to load configuration !");
610 display_tree(&rootmenu);
613 void on_load1_activate(GtkMenuItem * menuitem, gpointer user_data)
617 fs = gtk_file_selection_new("Load file...");
618 g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs)->ok_button),
620 G_CALLBACK(load_filename), (gpointer) fs);
621 g_signal_connect_swapped(GTK_OBJECT
622 (GTK_FILE_SELECTION(fs)->ok_button),
623 "clicked", G_CALLBACK(gtk_widget_destroy),
625 g_signal_connect_swapped(GTK_OBJECT
626 (GTK_FILE_SELECTION(fs)->cancel_button),
627 "clicked", G_CALLBACK(gtk_widget_destroy),
633 void on_save1_activate(GtkMenuItem * menuitem, gpointer user_data)
635 if (conf_write(NULL))
636 text_insert_msg("Error", "Unable to save configuration !");
638 config_changed = FALSE;
643 store_filename(GtkFileSelection * file_selector, gpointer user_data)
647 fn = gtk_file_selection_get_filename(GTK_FILE_SELECTION
651 text_insert_msg("Error", "Unable to save configuration !");
653 gtk_widget_destroy(GTK_WIDGET(user_data));
656 void on_save_as1_activate(GtkMenuItem * menuitem, gpointer user_data)
660 fs = gtk_file_selection_new("Save file as...");
661 g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs)->ok_button),
663 G_CALLBACK(store_filename), (gpointer) fs);
664 g_signal_connect_swapped(GTK_OBJECT
665 (GTK_FILE_SELECTION(fs)->ok_button),
666 "clicked", G_CALLBACK(gtk_widget_destroy),
668 g_signal_connect_swapped(GTK_OBJECT
669 (GTK_FILE_SELECTION(fs)->cancel_button),
670 "clicked", G_CALLBACK(gtk_widget_destroy),
676 void on_quit1_activate(GtkMenuItem * menuitem, gpointer user_data)
678 if (!on_window1_delete_event(NULL, NULL, NULL))
679 gtk_widget_destroy(GTK_WIDGET(main_wnd));
683 void on_show_name1_activate(GtkMenuItem * menuitem, gpointer user_data)
685 GtkTreeViewColumn *col;
687 show_name = GTK_CHECK_MENU_ITEM(menuitem)->active;
688 col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_NAME);
690 gtk_tree_view_column_set_visible(col, show_name);
694 void on_show_range1_activate(GtkMenuItem * menuitem, gpointer user_data)
696 GtkTreeViewColumn *col;
698 show_range = GTK_CHECK_MENU_ITEM(menuitem)->active;
699 col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_NO);
701 gtk_tree_view_column_set_visible(col, show_range);
702 col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_MOD);
704 gtk_tree_view_column_set_visible(col, show_range);
705 col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_YES);
707 gtk_tree_view_column_set_visible(col, show_range);
712 void on_show_data1_activate(GtkMenuItem * menuitem, gpointer user_data)
714 GtkTreeViewColumn *col;
716 show_value = GTK_CHECK_MENU_ITEM(menuitem)->active;
717 col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_VALUE);
719 gtk_tree_view_column_set_visible(col, show_value);
724 on_show_all_options1_activate(GtkMenuItem * menuitem, gpointer user_data)
726 show_all = GTK_CHECK_MENU_ITEM(menuitem)->active;
728 gtk_tree_store_clear(tree2);
729 display_tree(&rootmenu); // instead of update_tree to speed-up
734 on_show_debug_info1_activate(GtkMenuItem * menuitem, gpointer user_data)
736 show_debug = GTK_CHECK_MENU_ITEM(menuitem)->active;
737 update_tree(&rootmenu, NULL);
741 void on_introduction1_activate(GtkMenuItem * menuitem, gpointer user_data)
744 const gchar *intro_text =
745 "Welcome to gkc, the GTK+ graphical kernel configuration tool\n"
747 "For each option, a blank box indicates the feature is disabled, a\n"
748 "check indicates it is enabled, and a dot indicates that it is to\n"
749 "be compiled as a module. Clicking on the box will cycle through the three states.\n"
751 "If you do not see an option (e.g., a device driver) that you\n"
752 "believe should be present, try turning on Show All Options\n"
753 "under the Options menu.\n"
754 "Although there is no cross reference yet to help you figure out\n"
755 "what other options must be enabled to support the option you\n"
756 "are interested in, you can still view the help of a grayed-out\n"
759 "Toggling Show Debug Info under the Options menu will show \n"
760 "the dependencies, which you can then match by examining other options.";
762 dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
763 GTK_DIALOG_DESTROY_WITH_PARENT,
765 GTK_BUTTONS_CLOSE, intro_text);
766 g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
767 G_CALLBACK(gtk_widget_destroy),
769 gtk_widget_show_all(dialog);
773 void on_about1_activate(GtkMenuItem * menuitem, gpointer user_data)
776 const gchar *about_text =
777 "gkc is copyright (c) 2002 Romain Lievin <roms@lpg.ticalc.org>.\n"
778 "Based on the source code from Roman Zippel.\n";
780 dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
781 GTK_DIALOG_DESTROY_WITH_PARENT,
783 GTK_BUTTONS_CLOSE, about_text);
784 g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
785 G_CALLBACK(gtk_widget_destroy),
787 gtk_widget_show_all(dialog);
791 void on_license1_activate(GtkMenuItem * menuitem, gpointer user_data)
794 const gchar *license_text =
795 "gkc is released under the terms of the GNU GPL v2.\n"
796 "For more information, please see the source code or\n"
797 "visit http://www.fsf.org/licenses/licenses.html\n";
799 dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
800 GTK_DIALOG_DESTROY_WITH_PARENT,
802 GTK_BUTTONS_CLOSE, license_text);
803 g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
804 G_CALLBACK(gtk_widget_destroy),
806 gtk_widget_show_all(dialog);
810 void on_back_pressed(GtkButton * button, gpointer user_data)
812 enum prop_type ptype;
814 current = current->parent;
815 ptype = current->prompt ? current->prompt->type : P_UNKNOWN;
817 current = current->parent;
820 if (current == &rootmenu)
821 gtk_widget_set_sensitive(back_btn, FALSE);
825 void on_load_pressed(GtkButton * button, gpointer user_data)
827 on_load1_activate(NULL, user_data);
831 void on_save_pressed(GtkButton * button, gpointer user_data)
833 on_save1_activate(NULL, user_data);
837 void on_single_clicked(GtkButton * button, gpointer user_data)
839 view_mode = SINGLE_VIEW;
840 gtk_paned_set_position(GTK_PANED(hpaned), 0);
841 gtk_widget_hide(tree1_w);
847 void on_split_clicked(GtkButton * button, gpointer user_data)
850 view_mode = SPLIT_VIEW;
851 gtk_widget_show(tree1_w);
852 gtk_window_get_default_size(GTK_WINDOW(main_wnd), &w, &h);
853 gtk_paned_set_position(GTK_PANED(hpaned), w / 2);
855 gtk_tree_store_clear(tree2);
860 void on_full_clicked(GtkButton * button, gpointer user_data)
862 view_mode = FULL_VIEW;
863 gtk_paned_set_position(GTK_PANED(hpaned), 0);
864 gtk_widget_hide(tree1_w);
866 gtk_tree_store_clear(tree2);
867 display_tree(&rootmenu);
868 gtk_widget_set_sensitive(back_btn, FALSE);
872 void on_collapse_pressed(GtkButton * button, gpointer user_data)
874 gtk_tree_view_collapse_all(GTK_TREE_VIEW(tree2_w));
878 void on_expand_pressed(GtkButton * button, gpointer user_data)
880 gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w));
884 /* CTree Callbacks */
886 /* Change hex/int/string value in the cell */
887 static void renderer_edited(GtkCellRendererText * cell,
888 const gchar * path_string,
889 const gchar * new_text, gpointer user_data)
891 GtkTreePath *path = gtk_tree_path_new_from_string(path_string);
893 const char *old_def, *new_def;
897 if (!gtk_tree_model_get_iter(model2, &iter, path))
900 gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
903 gtk_tree_model_get(model2, &iter, COL_VALUE, &old_def, -1);
906 sym_set_string_value(sym, new_def);
908 config_changed = TRUE;
909 update_tree(&rootmenu, NULL);
911 gtk_tree_path_free(path);
914 /* Change the value of a symbol and update the tree */
915 static void change_sym_value(struct menu *menu, gint col)
917 struct symbol *sym = menu->sym;
918 tristate oldval, newval;
925 else if (col == COL_MOD)
927 else if (col == COL_YES)
932 switch (sym_get_type(sym)) {
935 oldval = sym_get_tristate_value(sym);
936 if (!sym_tristate_within_range(sym, newval))
938 sym_set_tristate_value(sym, newval);
939 config_changed = TRUE;
940 if (view_mode == FULL_VIEW)
941 update_tree(&rootmenu, NULL);
942 else if (view_mode == SPLIT_VIEW) {
943 update_tree(browsed, NULL);
946 else if (view_mode == SINGLE_VIEW)
947 display_tree_part(); //fixme: keep exp/coll
957 static void toggle_sym_value(struct menu *menu)
962 sym_toggle_tristate_value(menu->sym);
963 if (view_mode == FULL_VIEW)
964 update_tree(&rootmenu, NULL);
965 else if (view_mode == SPLIT_VIEW) {
966 update_tree(browsed, NULL);
969 else if (view_mode == SINGLE_VIEW)
970 display_tree_part(); //fixme: keep exp/coll
973 static void renderer_toggled(GtkCellRendererToggle * cell,
974 gchar * path_string, gpointer user_data)
976 GtkTreePath *path, *sel_path = NULL;
977 GtkTreeIter iter, sel_iter;
978 GtkTreeSelection *sel;
981 path = gtk_tree_path_new_from_string(path_string);
982 if (!gtk_tree_model_get_iter(model2, &iter, path))
985 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree2_w));
986 if (gtk_tree_selection_get_selected(sel, NULL, &sel_iter))
987 sel_path = gtk_tree_model_get_path(model2, &sel_iter);
990 if (gtk_tree_path_compare(path, sel_path))
993 gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
994 toggle_sym_value(menu);
997 gtk_tree_path_free(sel_path);
999 gtk_tree_path_free(path);
1002 static gint column2index(GtkTreeViewColumn * column)
1006 for (i = 0; i < COL_NUMBER; i++) {
1007 GtkTreeViewColumn *col;
1009 col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), i);
1018 /* User click: update choice (full) or goes down (single) */
1020 on_treeview2_button_press_event(GtkWidget * widget,
1021 GdkEventButton * event, gpointer user_data)
1023 GtkTreeView *view = GTK_TREE_VIEW(widget);
1025 GtkTreeViewColumn *column;
1030 #if GTK_CHECK_VERSION(2,1,4) // bug in ctree with earlier version of GTK
1031 gint tx = (gint) event->x;
1032 gint ty = (gint) event->y;
1035 gtk_tree_view_get_path_at_pos(view, tx, ty, &path, &column, &cx,
1038 gtk_tree_view_get_cursor(view, &path, &column);
1043 if (!gtk_tree_model_get_iter(model2, &iter, path))
1045 gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
1047 col = column2index(column);
1048 if (event->type == GDK_2BUTTON_PRESS) {
1049 enum prop_type ptype;
1050 ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
1052 if (ptype == P_MENU && view_mode != FULL_VIEW && col == COL_OPTION) {
1053 // goes down into menu
1055 display_tree_part();
1056 gtk_widget_set_sensitive(back_btn, TRUE);
1057 } else if ((col == COL_OPTION)) {
1058 toggle_sym_value(menu);
1059 gtk_tree_view_expand_row(view, path, TRUE);
1062 if (col == COL_VALUE) {
1063 toggle_sym_value(menu);
1064 gtk_tree_view_expand_row(view, path, TRUE);
1065 } else if (col == COL_NO || col == COL_MOD
1066 || col == COL_YES) {
1067 change_sym_value(menu, col);
1068 gtk_tree_view_expand_row(view, path, TRUE);
1075 /* Key pressed: update choice */
1077 on_treeview2_key_press_event(GtkWidget * widget,
1078 GdkEventKey * event, gpointer user_data)
1080 GtkTreeView *view = GTK_TREE_VIEW(widget);
1082 GtkTreeViewColumn *column;
1087 gtk_tree_view_get_cursor(view, &path, &column);
1091 if (event->keyval == GDK_space) {
1092 if (gtk_tree_view_row_expanded(view, path))
1093 gtk_tree_view_collapse_row(view, path);
1095 gtk_tree_view_expand_row(view, path, FALSE);
1098 if (event->keyval == GDK_KP_Enter) {
1100 if (widget == tree1_w)
1103 gtk_tree_model_get_iter(model2, &iter, path);
1104 gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
1106 if (!strcasecmp(event->string, "n"))
1108 else if (!strcasecmp(event->string, "m"))
1110 else if (!strcasecmp(event->string, "y"))
1114 change_sym_value(menu, col);
1120 /* Row selection changed: update help */
1122 on_treeview2_cursor_changed(GtkTreeView * treeview, gpointer user_data)
1124 GtkTreeSelection *selection;
1128 selection = gtk_tree_view_get_selection(treeview);
1129 if (gtk_tree_selection_get_selected(selection, &model2, &iter)) {
1130 gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
1131 text_insert_help(menu);
1136 /* User click: display sub-tree in the right frame. */
1138 on_treeview1_button_press_event(GtkWidget * widget,
1139 GdkEventButton * event, gpointer user_data)
1141 GtkTreeView *view = GTK_TREE_VIEW(widget);
1143 GtkTreeViewColumn *column;
1147 gint tx = (gint) event->x;
1148 gint ty = (gint) event->y;
1151 gtk_tree_view_get_path_at_pos(view, tx, ty, &path, &column, &cx,
1156 gtk_tree_model_get_iter(model1, &iter, path);
1157 gtk_tree_model_get(model1, &iter, COL_MENU, &menu, -1);
1159 if (event->type == GDK_2BUTTON_PRESS) {
1160 toggle_sym_value(menu);
1162 display_tree_part();
1165 display_tree_part();
1168 gtk_widget_realize(tree2_w);
1169 gtk_tree_view_set_cursor(view, path, NULL, FALSE);
1170 gtk_widget_grab_focus(tree2_w);
1176 /* Conf management */
1179 /* Fill a row of strings */
1180 static gchar **fill_row(struct menu *menu)
1182 static gchar *row[COL_NUMBER];
1183 struct symbol *sym = menu->sym;
1187 enum prop_type ptype;
1190 for (i = COL_OPTION; i <= COL_COLOR; i++)
1192 bzero(row, sizeof(row));
1195 g_strdup_printf("%s %s", menu_get_prompt(menu),
1197 flags & SYMBOL_NEW ? "(NEW)" : "") :
1200 if (show_all && !menu_is_visible(menu))
1201 row[COL_COLOR] = g_strdup("DarkGray");
1203 row[COL_COLOR] = g_strdup("Black");
1205 ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
1208 row[COL_PIXBUF] = (gchar *) xpm_menu;
1209 if (view_mode == SINGLE_VIEW)
1210 row[COL_PIXVIS] = GINT_TO_POINTER(TRUE);
1211 row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
1214 row[COL_PIXBUF] = (gchar *) xpm_void;
1215 row[COL_PIXVIS] = GINT_TO_POINTER(FALSE);
1216 row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
1219 row[COL_PIXBUF] = (gchar *) xpm_void;
1220 row[COL_PIXVIS] = GINT_TO_POINTER(FALSE);
1221 row[COL_BTNVIS] = GINT_TO_POINTER(TRUE);
1227 row[COL_NAME] = g_strdup(sym->name);
1229 sym_calc_value(sym);
1230 sym->flags &= ~SYMBOL_CHANGED;
1232 if (sym_is_choice(sym)) { // parse childs for getting final value
1234 struct symbol *def_sym = sym_get_choice_value(sym);
1235 struct menu *def_menu = NULL;
1237 row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
1239 for (child = menu->list; child; child = child->next) {
1240 if (menu_is_visible(child)
1241 && child->sym == def_sym)
1247 g_strdup(menu_get_prompt(def_menu));
1249 if(sym->flags & SYMBOL_CHOICEVAL)
1250 row[COL_BTNRAD] = GINT_TO_POINTER(TRUE);
1252 stype = sym_get_type(sym);
1255 if(GPOINTER_TO_INT(row[COL_PIXVIS]) == FALSE)
1256 row[COL_BTNVIS] = GINT_TO_POINTER(TRUE);
1257 if (sym_is_choice(sym))
1260 val = sym_get_tristate_value(sym);
1263 row[COL_NO] = g_strdup("N");
1264 row[COL_VALUE] = g_strdup("N");
1265 row[COL_BTNACT] = GINT_TO_POINTER(FALSE);
1266 row[COL_BTNINC] = GINT_TO_POINTER(FALSE);
1269 row[COL_MOD] = g_strdup("M");
1270 row[COL_VALUE] = g_strdup("M");
1271 row[COL_BTNINC] = GINT_TO_POINTER(TRUE);
1274 row[COL_YES] = g_strdup("Y");
1275 row[COL_VALUE] = g_strdup("Y");
1276 row[COL_BTNACT] = GINT_TO_POINTER(TRUE);
1277 row[COL_BTNINC] = GINT_TO_POINTER(FALSE);
1281 if (val != no && sym_tristate_within_range(sym, no))
1282 row[COL_NO] = g_strdup("_");
1283 if (val != mod && sym_tristate_within_range(sym, mod))
1284 row[COL_MOD] = g_strdup("_");
1285 if (val != yes && sym_tristate_within_range(sym, yes))
1286 row[COL_YES] = g_strdup("_");
1291 def = sym_get_string_value(sym);
1292 row[COL_VALUE] = g_strdup(def);
1293 row[COL_EDIT] = GINT_TO_POINTER(TRUE);
1294 row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
1302 /* Set the node content with a row of strings */
1303 static void set_node(GtkTreeIter * node, struct menu *menu, gchar ** row)
1309 pix = gdk_pixbuf_new_from_xpm_data((const char **)
1312 gdk_color_parse(row[COL_COLOR], &color);
1313 gdk_colormap_alloc_colors(gdk_colormap_get_system(), &color, 1,
1314 FALSE, FALSE, &success);
1316 gtk_tree_store_set(tree, node,
1317 COL_OPTION, row[COL_OPTION],
1318 COL_NAME, row[COL_NAME],
1319 COL_NO, row[COL_NO],
1320 COL_MOD, row[COL_MOD],
1321 COL_YES, row[COL_YES],
1322 COL_VALUE, row[COL_VALUE],
1323 COL_MENU, (gpointer) menu,
1325 COL_EDIT, GPOINTER_TO_INT(row[COL_EDIT]),
1327 COL_PIXVIS, GPOINTER_TO_INT(row[COL_PIXVIS]),
1328 COL_BTNVIS, GPOINTER_TO_INT(row[COL_BTNVIS]),
1329 COL_BTNACT, GPOINTER_TO_INT(row[COL_BTNACT]),
1330 COL_BTNINC, GPOINTER_TO_INT(row[COL_BTNINC]),
1331 COL_BTNRAD, GPOINTER_TO_INT(row[COL_BTNRAD]),
1334 g_object_unref(pix);
1338 /* Add a node to the tree */
1339 static void place_node(struct menu *menu, char **row)
1341 GtkTreeIter *parent = parents[indent - 1];
1342 GtkTreeIter *node = parents[indent];
1344 gtk_tree_store_append(tree, node, parent);
1345 set_node(node, menu, row);
1349 /* Find a node in the GTK+ tree */
1350 static GtkTreeIter found;
1353 * Find a menu in the GtkTree starting at parent.
1355 GtkTreeIter *gtktree_iter_find_node(GtkTreeIter * parent,
1356 struct menu *tofind)
1359 GtkTreeIter *child = &iter;
1363 valid = gtk_tree_model_iter_children(model2, child, parent);
1367 gtk_tree_model_get(model2, child, 6, &menu, -1);
1369 if (menu == tofind) {
1370 memcpy(&found, child, sizeof(GtkTreeIter));
1374 ret = gtktree_iter_find_node(child, tofind);
1378 valid = gtk_tree_model_iter_next(model2, child);
1386 * Update the tree by adding/removing entries
1387 * Does not change other nodes
1389 static void update_tree(struct menu *src, GtkTreeIter * dst)
1391 struct menu *child1;
1392 GtkTreeIter iter, tmp;
1393 GtkTreeIter *child2 = &iter;
1395 GtkTreeIter *sibling;
1397 struct property *prop;
1398 struct menu *menu1, *menu2;
1400 if (src == &rootmenu)
1403 valid = gtk_tree_model_iter_children(model2, child2, dst);
1404 for (child1 = src->list; child1; child1 = child1->next) {
1406 prop = child1->prompt;
1412 gtk_tree_model_get(model2, child2, COL_MENU,
1415 menu2 = NULL; // force adding of a first child
1418 printf("%*c%s | %s\n", indent, ' ',
1419 menu1 ? menu_get_prompt(menu1) : "nil",
1420 menu2 ? menu_get_prompt(menu2) : "nil");
1423 if (!menu_is_visible(child1) && !show_all) { // remove node
1424 if (gtktree_iter_find_node(dst, menu1) != NULL) {
1425 memcpy(&tmp, child2, sizeof(GtkTreeIter));
1426 valid = gtk_tree_model_iter_next(model2,
1428 gtk_tree_store_remove(tree2, &tmp);
1430 return; // next parent
1432 goto reparse; // next child
1437 if (menu1 != menu2) {
1438 if (gtktree_iter_find_node(dst, menu1) == NULL) { // add node
1439 if (!valid && !menu2)
1443 gtk_tree_store_insert_before(tree2,
1446 set_node(child2, menu1, fill_row(menu1));
1449 } else { // remove node
1450 memcpy(&tmp, child2, sizeof(GtkTreeIter));
1451 valid = gtk_tree_model_iter_next(model2,
1453 gtk_tree_store_remove(tree2, &tmp);
1455 return; // next parent
1457 goto reparse; // next child
1459 } else if (sym && (sym->flags & SYMBOL_CHANGED)) {
1460 set_node(child2, menu1, fill_row(menu1));
1464 update_tree(child1, child2);
1467 valid = gtk_tree_model_iter_next(model2, child2);
1472 /* Display the whole tree (single/split/full view) */
1473 static void display_tree(struct menu *menu)
1476 struct property *prop;
1478 enum prop_type ptype;
1480 if (menu == &rootmenu) {
1482 current = &rootmenu;
1485 for (child = menu->list; child; child = child->next) {
1486 prop = child->prompt;
1488 ptype = prop ? prop->type : P_UNKNOWN;
1491 sym->flags &= ~SYMBOL_CHANGED;
1493 if ((view_mode == SPLIT_VIEW) && !(child->flags & MENU_ROOT) &&
1497 if ((view_mode == SPLIT_VIEW) && (child->flags & MENU_ROOT) &&
1501 if (menu_is_visible(child) || show_all)
1502 place_node(child, fill_row(child));
1504 printf("%*c%s: ", indent, ' ', menu_get_prompt(child));
1505 printf("%s", child->flags & MENU_ROOT ? "rootmenu | " : "");
1506 dbg_print_ptype(ptype);
1509 dbg_print_stype(sym->type);
1511 dbg_print_flags(sym->flags);
1516 if ((view_mode != FULL_VIEW) && (ptype == P_MENU)
1520 if (((menu != &rootmenu) && !(menu->flags & MENU_ROOT)) ||
1521 (view_mode == FULL_VIEW)
1522 || (view_mode == SPLIT_VIEW))*/
1523 if (((view_mode == SINGLE_VIEW) && (menu->flags & MENU_ROOT))
1524 || (view_mode == FULL_VIEW) || (view_mode == SPLIT_VIEW)) {
1526 display_tree(child);
1532 /* Display a part of the tree starting at current node (single/split view) */
1533 static void display_tree_part(void)
1536 gtk_tree_store_clear(tree2);
1537 if(view_mode == SINGLE_VIEW)
1538 display_tree(current);
1539 else if(view_mode == SPLIT_VIEW)
1540 display_tree(browsed);
1541 gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w));
1544 /* Display the list in the left frame (split view) */
1545 static void display_list(void)
1548 gtk_tree_store_clear(tree1);
1551 display_tree(&rootmenu);
1552 gtk_tree_view_expand_all(GTK_TREE_VIEW(tree1_w));
1556 void fixup_rootmenu(struct menu *menu)
1559 static int menu_cnt = 0;
1561 menu->flags |= MENU_ROOT;
1562 for (child = menu->list; child; child = child->next) {
1563 if (child->prompt && child->prompt->type == P_MENU) {
1565 fixup_rootmenu(child);
1567 } else if (!menu_cnt)
1568 fixup_rootmenu(child);
1576 int main(int ac, char *av[])
1582 #ifndef LKC_DIRECT_LINK
1591 //add_pixmap_directory (PACKAGE_DATA_DIR "/" PACKAGE "/pixmaps");
1592 //add_pixmap_directory (PACKAGE_SOURCE_DIR "/pixmaps");
1594 /* Determine GUI path */
1595 env = getenv(SRCTREE);
1597 glade_file = g_strconcat(env, "/scripts/kconfig/gconf.glade", NULL);
1598 else if (av[0][0] == '/')
1599 glade_file = g_strconcat(av[0], ".glade", NULL);
1601 glade_file = g_strconcat(g_get_current_dir(), "/", av[0], ".glade", NULL);
1603 /* Load the interface and connect signals */
1604 init_main_window(glade_file);
1610 if (ac > 1 && av[1][0] == '-') {
1617 printf("%s <config>\n", av[0]);
1625 fixup_rootmenu(&rootmenu);
1628 switch (view_mode) {
1630 display_tree_part();
1636 display_tree(&rootmenu);