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 char nohelp_text[] =
42 N_("Sorry, no help available for this option yet.\n");
44 GtkWidget *main_wnd = NULL;
45 GtkWidget *tree1_w = NULL; // left frame
46 GtkWidget *tree2_w = NULL; // right frame
47 GtkWidget *text_w = NULL;
48 GtkWidget *hpaned = NULL;
49 GtkWidget *vpaned = NULL;
50 GtkWidget *back_btn = NULL;
51 GtkWidget *save_btn = NULL;
52 GtkWidget *save_menu_item = 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);
78 static void conf_changed(void);
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_CONST)
118 strcat(buf, "const/");
119 if (val & SYMBOL_CHECK)
120 strcat(buf, "check/");
121 if (val & SYMBOL_CHOICE)
122 strcat(buf, "choice/");
123 if (val & SYMBOL_CHOICEVAL)
124 strcat(buf, "choiceval/");
125 if (val & SYMBOL_PRINTED)
126 strcat(buf, "printed/");
127 if (val & SYMBOL_VALID)
128 strcat(buf, "valid/");
129 if (val & SYMBOL_OPTIONAL)
130 strcat(buf, "optional/");
131 if (val & SYMBOL_WRITE)
132 strcat(buf, "write/");
133 if (val & SYMBOL_CHANGED)
134 strcat(buf, "changed/");
135 if (val & SYMBOL_AUTO)
136 strcat(buf, "auto/");
138 buf[strlen(buf) - 1] = '\0';
146 const char *dbg_print_ptype(int val)
148 static char buf[256];
152 if (val == P_UNKNOWN)
153 strcpy(buf, "unknown");
155 strcpy(buf, "prompt");
156 if (val == P_COMMENT)
157 strcpy(buf, "comment");
160 if (val == P_DEFAULT)
161 strcpy(buf, "default");
163 strcpy(buf, "choice");
173 void replace_button_icon(GladeXML * xml, GdkDrawable * window,
174 GtkStyle * style, gchar * btn_name, gchar ** xpm)
178 GtkToolButton *button;
181 pixmap = gdk_pixmap_create_from_xpm_d(window, &mask,
182 &style->bg[GTK_STATE_NORMAL],
185 button = GTK_TOOL_BUTTON(glade_xml_get_widget(xml, btn_name));
186 image = gtk_image_new_from_pixmap(pixmap, mask);
187 gtk_widget_show(image);
188 gtk_tool_button_set_icon_widget(button, image);
191 /* Main Window Initialization */
192 void init_main_window(const gchar * glade_file)
196 GtkTextBuffer *txtbuf;
200 xml = glade_xml_new(glade_file, "window1", NULL);
202 g_error(_("GUI loading failed !\n"));
203 glade_xml_signal_autoconnect(xml);
205 main_wnd = glade_xml_get_widget(xml, "window1");
206 hpaned = glade_xml_get_widget(xml, "hpaned1");
207 vpaned = glade_xml_get_widget(xml, "vpaned1");
208 tree1_w = glade_xml_get_widget(xml, "treeview1");
209 tree2_w = glade_xml_get_widget(xml, "treeview2");
210 text_w = glade_xml_get_widget(xml, "textview3");
212 back_btn = glade_xml_get_widget(xml, "button1");
213 gtk_widget_set_sensitive(back_btn, FALSE);
215 widget = glade_xml_get_widget(xml, "show_name1");
216 gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget,
219 widget = glade_xml_get_widget(xml, "show_range1");
220 gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget,
223 widget = glade_xml_get_widget(xml, "show_data1");
224 gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget,
227 save_btn = glade_xml_get_widget(xml, "button3");
228 save_menu_item = glade_xml_get_widget(xml, "save1");
229 conf_set_changed_callback(conf_changed);
231 style = gtk_widget_get_style(main_wnd);
232 widget = glade_xml_get_widget(xml, "toolbar1");
234 #if 0 /* Use stock Gtk icons instead */
235 replace_button_icon(xml, main_wnd->window, style,
236 "button1", (gchar **) xpm_back);
237 replace_button_icon(xml, main_wnd->window, style,
238 "button2", (gchar **) xpm_load);
239 replace_button_icon(xml, main_wnd->window, style,
240 "button3", (gchar **) xpm_save);
242 replace_button_icon(xml, main_wnd->window, style,
243 "button4", (gchar **) xpm_single_view);
244 replace_button_icon(xml, main_wnd->window, style,
245 "button5", (gchar **) xpm_split_view);
246 replace_button_icon(xml, main_wnd->window, style,
247 "button6", (gchar **) xpm_tree_view);
252 widget = glade_xml_get_widget(xml, "button4");
253 g_signal_emit_by_name(widget, "clicked");
256 widget = glade_xml_get_widget(xml, "button5");
257 g_signal_emit_by_name(widget, "clicked");
260 widget = glade_xml_get_widget(xml, "button6");
261 g_signal_emit_by_name(widget, "clicked");
265 txtbuf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w));
266 tag1 = gtk_text_buffer_create_tag(txtbuf, "mytag1",
268 "weight", PANGO_WEIGHT_BOLD,
270 tag2 = gtk_text_buffer_create_tag(txtbuf, "mytag2",
271 /*"style", PANGO_STYLE_OBLIQUE, */
274 sprintf(title, _("Linux Kernel v%s Configuration"),
275 getenv("KERNELVERSION"));
276 gtk_window_set_title(GTK_WINDOW(main_wnd), title);
278 gtk_widget_show(main_wnd);
281 void init_tree_model(void)
285 tree = tree2 = gtk_tree_store_new(COL_NUMBER,
286 G_TYPE_STRING, G_TYPE_STRING,
287 G_TYPE_STRING, G_TYPE_STRING,
288 G_TYPE_STRING, G_TYPE_STRING,
289 G_TYPE_POINTER, GDK_TYPE_COLOR,
290 G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF,
291 G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
292 G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
294 model2 = GTK_TREE_MODEL(tree2);
296 for (parents[0] = NULL, i = 1; i < 256; i++)
297 parents[i] = (GtkTreeIter *) g_malloc(sizeof(GtkTreeIter));
299 tree1 = gtk_tree_store_new(COL_NUMBER,
300 G_TYPE_STRING, G_TYPE_STRING,
301 G_TYPE_STRING, G_TYPE_STRING,
302 G_TYPE_STRING, G_TYPE_STRING,
303 G_TYPE_POINTER, GDK_TYPE_COLOR,
304 G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF,
305 G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
306 G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
308 model1 = GTK_TREE_MODEL(tree1);
311 void init_left_tree(void)
313 GtkTreeView *view = GTK_TREE_VIEW(tree1_w);
314 GtkCellRenderer *renderer;
315 GtkTreeSelection *sel;
316 GtkTreeViewColumn *column;
318 gtk_tree_view_set_model(view, model1);
319 gtk_tree_view_set_headers_visible(view, TRUE);
320 gtk_tree_view_set_rules_hint(view, FALSE);
322 column = gtk_tree_view_column_new();
323 gtk_tree_view_append_column(view, column);
324 gtk_tree_view_column_set_title(column, _("Options"));
326 renderer = gtk_cell_renderer_toggle_new();
327 gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
329 gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
331 "active", COL_BTNACT,
332 "inconsistent", COL_BTNINC,
333 "visible", COL_BTNVIS,
334 "radio", COL_BTNRAD, NULL);
335 renderer = gtk_cell_renderer_text_new();
336 gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
338 gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
344 sel = gtk_tree_view_get_selection(view);
345 gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
346 gtk_widget_realize(tree1_w);
349 static void renderer_edited(GtkCellRendererText * cell,
350 const gchar * path_string,
351 const gchar * new_text, gpointer user_data);
352 static void renderer_toggled(GtkCellRendererToggle * cellrenderertoggle,
353 gchar * arg1, gpointer user_data);
355 void init_right_tree(void)
357 GtkTreeView *view = GTK_TREE_VIEW(tree2_w);
358 GtkCellRenderer *renderer;
359 GtkTreeSelection *sel;
360 GtkTreeViewColumn *column;
363 gtk_tree_view_set_model(view, model2);
364 gtk_tree_view_set_headers_visible(view, TRUE);
365 gtk_tree_view_set_rules_hint(view, FALSE);
367 column = gtk_tree_view_column_new();
368 gtk_tree_view_append_column(view, column);
369 gtk_tree_view_column_set_title(column, _("Options"));
371 renderer = gtk_cell_renderer_pixbuf_new();
372 gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
374 gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
376 "pixbuf", COL_PIXBUF,
377 "visible", COL_PIXVIS, NULL);
378 renderer = gtk_cell_renderer_toggle_new();
379 gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
381 gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
383 "active", COL_BTNACT,
384 "inconsistent", COL_BTNINC,
385 "visible", COL_BTNVIS,
386 "radio", COL_BTNRAD, NULL);
387 /*g_signal_connect(G_OBJECT(renderer), "toggled",
388 G_CALLBACK(renderer_toggled), NULL); */
389 renderer = gtk_cell_renderer_text_new();
390 gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
392 gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
398 renderer = gtk_cell_renderer_text_new();
399 gtk_tree_view_insert_column_with_attributes(view, -1,
404 renderer = gtk_cell_renderer_text_new();
405 gtk_tree_view_insert_column_with_attributes(view, -1,
410 renderer = gtk_cell_renderer_text_new();
411 gtk_tree_view_insert_column_with_attributes(view, -1,
416 renderer = gtk_cell_renderer_text_new();
417 gtk_tree_view_insert_column_with_attributes(view, -1,
422 renderer = gtk_cell_renderer_text_new();
423 gtk_tree_view_insert_column_with_attributes(view, -1,
424 _("Value"), renderer,
430 g_signal_connect(G_OBJECT(renderer), "edited",
431 G_CALLBACK(renderer_edited), NULL);
433 column = gtk_tree_view_get_column(view, COL_NAME);
434 gtk_tree_view_column_set_visible(column, show_name);
435 column = gtk_tree_view_get_column(view, COL_NO);
436 gtk_tree_view_column_set_visible(column, show_range);
437 column = gtk_tree_view_get_column(view, COL_MOD);
438 gtk_tree_view_column_set_visible(column, show_range);
439 column = gtk_tree_view_get_column(view, COL_YES);
440 gtk_tree_view_column_set_visible(column, show_range);
441 column = gtk_tree_view_get_column(view, COL_VALUE);
442 gtk_tree_view_column_set_visible(column, show_value);
445 for (i = 0; i < COL_VALUE; i++) {
446 column = gtk_tree_view_get_column(view, i);
447 gtk_tree_view_column_set_resizable(column, TRUE);
451 sel = gtk_tree_view_get_selection(view);
452 gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
456 /* Utility Functions */
459 static void text_insert_help(struct menu *menu)
461 GtkTextBuffer *buffer;
462 GtkTextIter start, end;
463 const char *prompt = menu_get_prompt(menu);
465 const char *help = _(nohelp_text);
469 else if (menu->sym->help)
470 help = _(menu->sym->help);
472 if (menu->sym && menu->sym->name)
473 name = g_strdup_printf(_(menu->sym->name));
477 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w));
478 gtk_text_buffer_get_bounds(buffer, &start, &end);
479 gtk_text_buffer_delete(buffer, &start, &end);
480 gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_w), 15);
482 gtk_text_buffer_get_end_iter(buffer, &end);
483 gtk_text_buffer_insert_with_tags(buffer, &end, prompt, -1, tag1,
485 gtk_text_buffer_insert_at_cursor(buffer, " ", 1);
486 gtk_text_buffer_get_end_iter(buffer, &end);
487 gtk_text_buffer_insert_with_tags(buffer, &end, name, -1, tag1,
489 gtk_text_buffer_insert_at_cursor(buffer, "\n\n", 2);
490 gtk_text_buffer_get_end_iter(buffer, &end);
491 gtk_text_buffer_insert_with_tags(buffer, &end, help, -1, tag2,
496 static void text_insert_msg(const char *title, const char *message)
498 GtkTextBuffer *buffer;
499 GtkTextIter start, end;
500 const char *msg = message;
502 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w));
503 gtk_text_buffer_get_bounds(buffer, &start, &end);
504 gtk_text_buffer_delete(buffer, &start, &end);
505 gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_w), 15);
507 gtk_text_buffer_get_end_iter(buffer, &end);
508 gtk_text_buffer_insert_with_tags(buffer, &end, title, -1, tag1,
510 gtk_text_buffer_insert_at_cursor(buffer, "\n\n", 2);
511 gtk_text_buffer_get_end_iter(buffer, &end);
512 gtk_text_buffer_insert_with_tags(buffer, &end, msg, -1, tag2,
517 /* Main Windows Callbacks */
519 void on_save_activate(GtkMenuItem * menuitem, gpointer user_data);
520 gboolean on_window1_delete_event(GtkWidget * widget, GdkEvent * event,
523 GtkWidget *dialog, *label;
526 if (!conf_get_changed())
529 dialog = gtk_dialog_new_with_buttons(_("Warning !"),
530 GTK_WINDOW(main_wnd),
533 GTK_DIALOG_DESTROY_WITH_PARENT),
539 GTK_RESPONSE_CANCEL, NULL);
540 gtk_dialog_set_default_response(GTK_DIALOG(dialog),
541 GTK_RESPONSE_CANCEL);
543 label = gtk_label_new(_("\nSave configuration ?\n"));
544 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), label);
545 gtk_widget_show(label);
547 result = gtk_dialog_run(GTK_DIALOG(dialog));
549 case GTK_RESPONSE_YES:
550 on_save_activate(NULL, NULL);
552 case GTK_RESPONSE_NO:
554 case GTK_RESPONSE_CANCEL:
555 case GTK_RESPONSE_DELETE_EVENT:
557 gtk_widget_destroy(dialog);
565 void on_window1_destroy(GtkObject * object, gpointer user_data)
572 on_window1_size_request(GtkWidget * widget,
573 GtkRequisition * requisition, gpointer user_data)
578 if (widget->window == NULL)
579 gtk_window_get_default_size(GTK_WINDOW(main_wnd), &w, &h);
581 gdk_window_get_size(widget->window, &w, &h);
587 gtk_paned_set_position(GTK_PANED(vpaned), 2 * h / 3);
591 /* Menu & Toolbar Callbacks */
595 load_filename(GtkFileSelection * file_selector, gpointer user_data)
599 fn = gtk_file_selection_get_filename(GTK_FILE_SELECTION
603 text_insert_msg(_("Error"), _("Unable to load configuration !"));
605 display_tree(&rootmenu);
608 void on_load1_activate(GtkMenuItem * menuitem, gpointer user_data)
612 fs = gtk_file_selection_new(_("Load file..."));
613 g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs)->ok_button),
615 G_CALLBACK(load_filename), (gpointer) fs);
616 g_signal_connect_swapped(GTK_OBJECT
617 (GTK_FILE_SELECTION(fs)->ok_button),
618 "clicked", G_CALLBACK(gtk_widget_destroy),
620 g_signal_connect_swapped(GTK_OBJECT
621 (GTK_FILE_SELECTION(fs)->cancel_button),
622 "clicked", G_CALLBACK(gtk_widget_destroy),
628 void on_save_activate(GtkMenuItem * menuitem, gpointer user_data)
630 if (conf_write(NULL))
631 text_insert_msg(_("Error"), _("Unable to save configuration !"));
636 store_filename(GtkFileSelection * file_selector, gpointer user_data)
640 fn = gtk_file_selection_get_filename(GTK_FILE_SELECTION
644 text_insert_msg(_("Error"), _("Unable to save configuration !"));
646 gtk_widget_destroy(GTK_WIDGET(user_data));
649 void on_save_as1_activate(GtkMenuItem * menuitem, gpointer user_data)
653 fs = gtk_file_selection_new(_("Save file as..."));
654 g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs)->ok_button),
656 G_CALLBACK(store_filename), (gpointer) fs);
657 g_signal_connect_swapped(GTK_OBJECT
658 (GTK_FILE_SELECTION(fs)->ok_button),
659 "clicked", G_CALLBACK(gtk_widget_destroy),
661 g_signal_connect_swapped(GTK_OBJECT
662 (GTK_FILE_SELECTION(fs)->cancel_button),
663 "clicked", G_CALLBACK(gtk_widget_destroy),
669 void on_quit1_activate(GtkMenuItem * menuitem, gpointer user_data)
671 if (!on_window1_delete_event(NULL, NULL, NULL))
672 gtk_widget_destroy(GTK_WIDGET(main_wnd));
676 void on_show_name1_activate(GtkMenuItem * menuitem, gpointer user_data)
678 GtkTreeViewColumn *col;
680 show_name = GTK_CHECK_MENU_ITEM(menuitem)->active;
681 col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_NAME);
683 gtk_tree_view_column_set_visible(col, show_name);
687 void on_show_range1_activate(GtkMenuItem * menuitem, gpointer user_data)
689 GtkTreeViewColumn *col;
691 show_range = GTK_CHECK_MENU_ITEM(menuitem)->active;
692 col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_NO);
694 gtk_tree_view_column_set_visible(col, show_range);
695 col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_MOD);
697 gtk_tree_view_column_set_visible(col, show_range);
698 col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_YES);
700 gtk_tree_view_column_set_visible(col, show_range);
705 void on_show_data1_activate(GtkMenuItem * menuitem, gpointer user_data)
707 GtkTreeViewColumn *col;
709 show_value = GTK_CHECK_MENU_ITEM(menuitem)->active;
710 col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_VALUE);
712 gtk_tree_view_column_set_visible(col, show_value);
717 on_show_all_options1_activate(GtkMenuItem * menuitem, gpointer user_data)
719 show_all = GTK_CHECK_MENU_ITEM(menuitem)->active;
721 gtk_tree_store_clear(tree2);
722 display_tree(&rootmenu); // instead of update_tree to speed-up
727 on_show_debug_info1_activate(GtkMenuItem * menuitem, gpointer user_data)
729 show_debug = GTK_CHECK_MENU_ITEM(menuitem)->active;
730 update_tree(&rootmenu, NULL);
734 void on_introduction1_activate(GtkMenuItem * menuitem, gpointer user_data)
737 const gchar *intro_text = _(
738 "Welcome to gkc, the GTK+ graphical kernel configuration tool\n"
740 "For each option, a blank box indicates the feature is disabled, a\n"
741 "check indicates it is enabled, and a dot indicates that it is to\n"
742 "be compiled as a module. Clicking on the box will cycle through the three states.\n"
744 "If you do not see an option (e.g., a device driver) that you\n"
745 "believe should be present, try turning on Show All Options\n"
746 "under the Options menu.\n"
747 "Although there is no cross reference yet to help you figure out\n"
748 "what other options must be enabled to support the option you\n"
749 "are interested in, you can still view the help of a grayed-out\n"
752 "Toggling Show Debug Info under the Options menu will show \n"
753 "the dependencies, which you can then match by examining other options.");
755 dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
756 GTK_DIALOG_DESTROY_WITH_PARENT,
758 GTK_BUTTONS_CLOSE, intro_text);
759 g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
760 G_CALLBACK(gtk_widget_destroy),
762 gtk_widget_show_all(dialog);
766 void on_about1_activate(GtkMenuItem * menuitem, gpointer user_data)
769 const gchar *about_text =
770 _("gkc is copyright (c) 2002 Romain Lievin <roms@lpg.ticalc.org>.\n"
771 "Based on the source code from Roman Zippel.\n");
773 dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
774 GTK_DIALOG_DESTROY_WITH_PARENT,
776 GTK_BUTTONS_CLOSE, about_text);
777 g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
778 G_CALLBACK(gtk_widget_destroy),
780 gtk_widget_show_all(dialog);
784 void on_license1_activate(GtkMenuItem * menuitem, gpointer user_data)
787 const gchar *license_text =
788 _("gkc is released under the terms of the GNU GPL v2.\n"
789 "For more information, please see the source code or\n"
790 "visit http://www.fsf.org/licenses/licenses.html\n");
792 dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
793 GTK_DIALOG_DESTROY_WITH_PARENT,
795 GTK_BUTTONS_CLOSE, license_text);
796 g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
797 G_CALLBACK(gtk_widget_destroy),
799 gtk_widget_show_all(dialog);
803 void on_back_clicked(GtkButton * button, gpointer user_data)
805 enum prop_type ptype;
807 current = current->parent;
808 ptype = current->prompt ? current->prompt->type : P_UNKNOWN;
810 current = current->parent;
813 if (current == &rootmenu)
814 gtk_widget_set_sensitive(back_btn, FALSE);
818 void on_load_clicked(GtkButton * button, gpointer user_data)
820 on_load1_activate(NULL, user_data);
824 void on_single_clicked(GtkButton * button, gpointer user_data)
826 view_mode = SINGLE_VIEW;
827 gtk_paned_set_position(GTK_PANED(hpaned), 0);
828 gtk_widget_hide(tree1_w);
834 void on_split_clicked(GtkButton * button, gpointer user_data)
837 view_mode = SPLIT_VIEW;
838 gtk_widget_show(tree1_w);
839 gtk_window_get_default_size(GTK_WINDOW(main_wnd), &w, &h);
840 gtk_paned_set_position(GTK_PANED(hpaned), w / 2);
842 gtk_tree_store_clear(tree2);
845 /* Disable back btn, like in full mode. */
846 gtk_widget_set_sensitive(back_btn, FALSE);
850 void on_full_clicked(GtkButton * button, gpointer user_data)
852 view_mode = FULL_VIEW;
853 gtk_paned_set_position(GTK_PANED(hpaned), 0);
854 gtk_widget_hide(tree1_w);
856 gtk_tree_store_clear(tree2);
857 display_tree(&rootmenu);
858 gtk_widget_set_sensitive(back_btn, FALSE);
862 void on_collapse_clicked(GtkButton * button, gpointer user_data)
864 gtk_tree_view_collapse_all(GTK_TREE_VIEW(tree2_w));
868 void on_expand_clicked(GtkButton * button, gpointer user_data)
870 gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w));
874 /* CTree Callbacks */
876 /* Change hex/int/string value in the cell */
877 static void renderer_edited(GtkCellRendererText * cell,
878 const gchar * path_string,
879 const gchar * new_text, gpointer user_data)
881 GtkTreePath *path = gtk_tree_path_new_from_string(path_string);
883 const char *old_def, *new_def;
887 if (!gtk_tree_model_get_iter(model2, &iter, path))
890 gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
893 gtk_tree_model_get(model2, &iter, COL_VALUE, &old_def, -1);
896 sym_set_string_value(sym, new_def);
898 update_tree(&rootmenu, NULL);
900 gtk_tree_path_free(path);
903 /* Change the value of a symbol and update the tree */
904 static void change_sym_value(struct menu *menu, gint col)
906 struct symbol *sym = menu->sym;
907 tristate oldval, newval;
914 else if (col == COL_MOD)
916 else if (col == COL_YES)
921 switch (sym_get_type(sym)) {
924 oldval = sym_get_tristate_value(sym);
925 if (!sym_tristate_within_range(sym, newval))
927 sym_set_tristate_value(sym, newval);
928 if (view_mode == FULL_VIEW)
929 update_tree(&rootmenu, NULL);
930 else if (view_mode == SPLIT_VIEW) {
931 update_tree(browsed, NULL);
934 else if (view_mode == SINGLE_VIEW)
935 display_tree_part(); //fixme: keep exp/coll
945 static void toggle_sym_value(struct menu *menu)
950 sym_toggle_tristate_value(menu->sym);
951 if (view_mode == FULL_VIEW)
952 update_tree(&rootmenu, NULL);
953 else if (view_mode == SPLIT_VIEW) {
954 update_tree(browsed, NULL);
957 else if (view_mode == SINGLE_VIEW)
958 display_tree_part(); //fixme: keep exp/coll
961 static void renderer_toggled(GtkCellRendererToggle * cell,
962 gchar * path_string, gpointer user_data)
964 GtkTreePath *path, *sel_path = NULL;
965 GtkTreeIter iter, sel_iter;
966 GtkTreeSelection *sel;
969 path = gtk_tree_path_new_from_string(path_string);
970 if (!gtk_tree_model_get_iter(model2, &iter, path))
973 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree2_w));
974 if (gtk_tree_selection_get_selected(sel, NULL, &sel_iter))
975 sel_path = gtk_tree_model_get_path(model2, &sel_iter);
978 if (gtk_tree_path_compare(path, sel_path))
981 gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
982 toggle_sym_value(menu);
985 gtk_tree_path_free(sel_path);
987 gtk_tree_path_free(path);
990 static gint column2index(GtkTreeViewColumn * column)
994 for (i = 0; i < COL_NUMBER; i++) {
995 GtkTreeViewColumn *col;
997 col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), i);
1006 /* User click: update choice (full) or goes down (single) */
1008 on_treeview2_button_press_event(GtkWidget * widget,
1009 GdkEventButton * event, gpointer user_data)
1011 GtkTreeView *view = GTK_TREE_VIEW(widget);
1013 GtkTreeViewColumn *column;
1018 #if GTK_CHECK_VERSION(2,1,4) // bug in ctree with earlier version of GTK
1019 gint tx = (gint) event->x;
1020 gint ty = (gint) event->y;
1023 gtk_tree_view_get_path_at_pos(view, tx, ty, &path, &column, &cx,
1026 gtk_tree_view_get_cursor(view, &path, &column);
1031 if (!gtk_tree_model_get_iter(model2, &iter, path))
1033 gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
1035 col = column2index(column);
1036 if (event->type == GDK_2BUTTON_PRESS) {
1037 enum prop_type ptype;
1038 ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
1040 if (ptype == P_MENU && view_mode != FULL_VIEW && col == COL_OPTION) {
1041 // goes down into menu
1043 display_tree_part();
1044 gtk_widget_set_sensitive(back_btn, TRUE);
1045 } else if ((col == COL_OPTION)) {
1046 toggle_sym_value(menu);
1047 gtk_tree_view_expand_row(view, path, TRUE);
1050 if (col == COL_VALUE) {
1051 toggle_sym_value(menu);
1052 gtk_tree_view_expand_row(view, path, TRUE);
1053 } else if (col == COL_NO || col == COL_MOD
1054 || col == COL_YES) {
1055 change_sym_value(menu, col);
1056 gtk_tree_view_expand_row(view, path, TRUE);
1063 /* Key pressed: update choice */
1065 on_treeview2_key_press_event(GtkWidget * widget,
1066 GdkEventKey * event, gpointer user_data)
1068 GtkTreeView *view = GTK_TREE_VIEW(widget);
1070 GtkTreeViewColumn *column;
1075 gtk_tree_view_get_cursor(view, &path, &column);
1079 if (event->keyval == GDK_space) {
1080 if (gtk_tree_view_row_expanded(view, path))
1081 gtk_tree_view_collapse_row(view, path);
1083 gtk_tree_view_expand_row(view, path, FALSE);
1086 if (event->keyval == GDK_KP_Enter) {
1088 if (widget == tree1_w)
1091 gtk_tree_model_get_iter(model2, &iter, path);
1092 gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
1094 if (!strcasecmp(event->string, "n"))
1096 else if (!strcasecmp(event->string, "m"))
1098 else if (!strcasecmp(event->string, "y"))
1102 change_sym_value(menu, col);
1108 /* Row selection changed: update help */
1110 on_treeview2_cursor_changed(GtkTreeView * treeview, gpointer user_data)
1112 GtkTreeSelection *selection;
1116 selection = gtk_tree_view_get_selection(treeview);
1117 if (gtk_tree_selection_get_selected(selection, &model2, &iter)) {
1118 gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
1119 text_insert_help(menu);
1124 /* User click: display sub-tree in the right frame. */
1126 on_treeview1_button_press_event(GtkWidget * widget,
1127 GdkEventButton * event, gpointer user_data)
1129 GtkTreeView *view = GTK_TREE_VIEW(widget);
1131 GtkTreeViewColumn *column;
1135 gint tx = (gint) event->x;
1136 gint ty = (gint) event->y;
1139 gtk_tree_view_get_path_at_pos(view, tx, ty, &path, &column, &cx,
1144 gtk_tree_model_get_iter(model1, &iter, path);
1145 gtk_tree_model_get(model1, &iter, COL_MENU, &menu, -1);
1147 if (event->type == GDK_2BUTTON_PRESS) {
1148 toggle_sym_value(menu);
1150 display_tree_part();
1153 display_tree_part();
1156 gtk_widget_realize(tree2_w);
1157 gtk_tree_view_set_cursor(view, path, NULL, FALSE);
1158 gtk_widget_grab_focus(tree2_w);
1164 /* Fill a row of strings */
1165 static gchar **fill_row(struct menu *menu)
1167 static gchar *row[COL_NUMBER];
1168 struct symbol *sym = menu->sym;
1172 enum prop_type ptype;
1175 for (i = COL_OPTION; i <= COL_COLOR; i++)
1177 bzero(row, sizeof(row));
1180 g_strdup_printf("%s %s", menu_get_prompt(menu),
1181 sym && sym_has_value(sym) ? "(NEW)" : "");
1183 if (show_all && !menu_is_visible(menu))
1184 row[COL_COLOR] = g_strdup("DarkGray");
1186 row[COL_COLOR] = g_strdup("Black");
1188 ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
1191 row[COL_PIXBUF] = (gchar *) xpm_menu;
1192 if (view_mode == SINGLE_VIEW)
1193 row[COL_PIXVIS] = GINT_TO_POINTER(TRUE);
1194 row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
1197 row[COL_PIXBUF] = (gchar *) xpm_void;
1198 row[COL_PIXVIS] = GINT_TO_POINTER(FALSE);
1199 row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
1202 row[COL_PIXBUF] = (gchar *) xpm_void;
1203 row[COL_PIXVIS] = GINT_TO_POINTER(FALSE);
1204 row[COL_BTNVIS] = GINT_TO_POINTER(TRUE);
1210 row[COL_NAME] = g_strdup(sym->name);
1212 sym_calc_value(sym);
1213 sym->flags &= ~SYMBOL_CHANGED;
1215 if (sym_is_choice(sym)) { // parse childs for getting final value
1217 struct symbol *def_sym = sym_get_choice_value(sym);
1218 struct menu *def_menu = NULL;
1220 row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
1222 for (child = menu->list; child; child = child->next) {
1223 if (menu_is_visible(child)
1224 && child->sym == def_sym)
1230 g_strdup(menu_get_prompt(def_menu));
1232 if (sym->flags & SYMBOL_CHOICEVAL)
1233 row[COL_BTNRAD] = GINT_TO_POINTER(TRUE);
1235 stype = sym_get_type(sym);
1238 if (GPOINTER_TO_INT(row[COL_PIXVIS]) == FALSE)
1239 row[COL_BTNVIS] = GINT_TO_POINTER(TRUE);
1240 if (sym_is_choice(sym))
1243 val = sym_get_tristate_value(sym);
1246 row[COL_NO] = g_strdup("N");
1247 row[COL_VALUE] = g_strdup("N");
1248 row[COL_BTNACT] = GINT_TO_POINTER(FALSE);
1249 row[COL_BTNINC] = GINT_TO_POINTER(FALSE);
1252 row[COL_MOD] = g_strdup("M");
1253 row[COL_VALUE] = g_strdup("M");
1254 row[COL_BTNINC] = GINT_TO_POINTER(TRUE);
1257 row[COL_YES] = g_strdup("Y");
1258 row[COL_VALUE] = g_strdup("Y");
1259 row[COL_BTNACT] = GINT_TO_POINTER(TRUE);
1260 row[COL_BTNINC] = GINT_TO_POINTER(FALSE);
1264 if (val != no && sym_tristate_within_range(sym, no))
1265 row[COL_NO] = g_strdup("_");
1266 if (val != mod && sym_tristate_within_range(sym, mod))
1267 row[COL_MOD] = g_strdup("_");
1268 if (val != yes && sym_tristate_within_range(sym, yes))
1269 row[COL_YES] = g_strdup("_");
1274 def = sym_get_string_value(sym);
1275 row[COL_VALUE] = g_strdup(def);
1276 row[COL_EDIT] = GINT_TO_POINTER(TRUE);
1277 row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
1285 /* Set the node content with a row of strings */
1286 static void set_node(GtkTreeIter * node, struct menu *menu, gchar ** row)
1292 pix = gdk_pixbuf_new_from_xpm_data((const char **)
1295 gdk_color_parse(row[COL_COLOR], &color);
1296 gdk_colormap_alloc_colors(gdk_colormap_get_system(), &color, 1,
1297 FALSE, FALSE, &success);
1299 gtk_tree_store_set(tree, node,
1300 COL_OPTION, row[COL_OPTION],
1301 COL_NAME, row[COL_NAME],
1302 COL_NO, row[COL_NO],
1303 COL_MOD, row[COL_MOD],
1304 COL_YES, row[COL_YES],
1305 COL_VALUE, row[COL_VALUE],
1306 COL_MENU, (gpointer) menu,
1308 COL_EDIT, GPOINTER_TO_INT(row[COL_EDIT]),
1310 COL_PIXVIS, GPOINTER_TO_INT(row[COL_PIXVIS]),
1311 COL_BTNVIS, GPOINTER_TO_INT(row[COL_BTNVIS]),
1312 COL_BTNACT, GPOINTER_TO_INT(row[COL_BTNACT]),
1313 COL_BTNINC, GPOINTER_TO_INT(row[COL_BTNINC]),
1314 COL_BTNRAD, GPOINTER_TO_INT(row[COL_BTNRAD]),
1317 g_object_unref(pix);
1321 /* Add a node to the tree */
1322 static void place_node(struct menu *menu, char **row)
1324 GtkTreeIter *parent = parents[indent - 1];
1325 GtkTreeIter *node = parents[indent];
1327 gtk_tree_store_append(tree, node, parent);
1328 set_node(node, menu, row);
1332 /* Find a node in the GTK+ tree */
1333 static GtkTreeIter found;
1336 * Find a menu in the GtkTree starting at parent.
1338 GtkTreeIter *gtktree_iter_find_node(GtkTreeIter * parent,
1339 struct menu *tofind)
1342 GtkTreeIter *child = &iter;
1346 valid = gtk_tree_model_iter_children(model2, child, parent);
1350 gtk_tree_model_get(model2, child, 6, &menu, -1);
1352 if (menu == tofind) {
1353 memcpy(&found, child, sizeof(GtkTreeIter));
1357 ret = gtktree_iter_find_node(child, tofind);
1361 valid = gtk_tree_model_iter_next(model2, child);
1369 * Update the tree by adding/removing entries
1370 * Does not change other nodes
1372 static void update_tree(struct menu *src, GtkTreeIter * dst)
1374 struct menu *child1;
1375 GtkTreeIter iter, tmp;
1376 GtkTreeIter *child2 = &iter;
1378 GtkTreeIter *sibling;
1380 struct property *prop;
1381 struct menu *menu1, *menu2;
1383 if (src == &rootmenu)
1386 valid = gtk_tree_model_iter_children(model2, child2, dst);
1387 for (child1 = src->list; child1; child1 = child1->next) {
1389 prop = child1->prompt;
1395 gtk_tree_model_get(model2, child2, COL_MENU,
1398 menu2 = NULL; // force adding of a first child
1401 printf("%*c%s | %s\n", indent, ' ',
1402 menu1 ? menu_get_prompt(menu1) : "nil",
1403 menu2 ? menu_get_prompt(menu2) : "nil");
1406 if (!menu_is_visible(child1) && !show_all) { // remove node
1407 if (gtktree_iter_find_node(dst, menu1) != NULL) {
1408 memcpy(&tmp, child2, sizeof(GtkTreeIter));
1409 valid = gtk_tree_model_iter_next(model2,
1411 gtk_tree_store_remove(tree2, &tmp);
1413 return; // next parent
1415 goto reparse; // next child
1420 if (menu1 != menu2) {
1421 if (gtktree_iter_find_node(dst, menu1) == NULL) { // add node
1422 if (!valid && !menu2)
1426 gtk_tree_store_insert_before(tree2,
1429 set_node(child2, menu1, fill_row(menu1));
1432 } else { // remove node
1433 memcpy(&tmp, child2, sizeof(GtkTreeIter));
1434 valid = gtk_tree_model_iter_next(model2,
1436 gtk_tree_store_remove(tree2, &tmp);
1438 return; // next parent
1440 goto reparse; // next child
1442 } else if (sym && (sym->flags & SYMBOL_CHANGED)) {
1443 set_node(child2, menu1, fill_row(menu1));
1447 update_tree(child1, child2);
1450 valid = gtk_tree_model_iter_next(model2, child2);
1455 /* Display the whole tree (single/split/full view) */
1456 static void display_tree(struct menu *menu)
1459 struct property *prop;
1461 enum prop_type ptype;
1463 if (menu == &rootmenu) {
1465 current = &rootmenu;
1468 for (child = menu->list; child; child = child->next) {
1469 prop = child->prompt;
1471 ptype = prop ? prop->type : P_UNKNOWN;
1474 sym->flags &= ~SYMBOL_CHANGED;
1476 if ((view_mode == SPLIT_VIEW)
1477 && !(child->flags & MENU_ROOT) && (tree == tree1))
1480 if ((view_mode == SPLIT_VIEW) && (child->flags & MENU_ROOT)
1484 if (menu_is_visible(child) || show_all)
1485 place_node(child, fill_row(child));
1487 printf("%*c%s: ", indent, ' ', menu_get_prompt(child));
1488 printf("%s", child->flags & MENU_ROOT ? "rootmenu | " : "");
1489 dbg_print_ptype(ptype);
1492 dbg_print_stype(sym->type);
1494 dbg_print_flags(sym->flags);
1499 if ((view_mode != FULL_VIEW) && (ptype == P_MENU)
1503 if (((menu != &rootmenu) && !(menu->flags & MENU_ROOT))
1504 || (view_mode == FULL_VIEW)
1505 || (view_mode == SPLIT_VIEW))*/
1506 if (((view_mode == SINGLE_VIEW) && (menu->flags & MENU_ROOT))
1507 || (view_mode == FULL_VIEW)
1508 || (view_mode == SPLIT_VIEW)) {
1510 display_tree(child);
1516 /* Display a part of the tree starting at current node (single/split view) */
1517 static void display_tree_part(void)
1520 gtk_tree_store_clear(tree2);
1521 if (view_mode == SINGLE_VIEW)
1522 display_tree(current);
1523 else if (view_mode == SPLIT_VIEW)
1524 display_tree(browsed);
1525 gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w));
1528 /* Display the list in the left frame (split view) */
1529 static void display_list(void)
1532 gtk_tree_store_clear(tree1);
1535 display_tree(&rootmenu);
1536 gtk_tree_view_expand_all(GTK_TREE_VIEW(tree1_w));
1540 void fixup_rootmenu(struct menu *menu)
1543 static int menu_cnt = 0;
1545 menu->flags |= MENU_ROOT;
1546 for (child = menu->list; child; child = child->next) {
1547 if (child->prompt && child->prompt->type == P_MENU) {
1549 fixup_rootmenu(child);
1551 } else if (!menu_cnt)
1552 fixup_rootmenu(child);
1558 int main(int ac, char *av[])
1564 #ifndef LKC_DIRECT_LINK
1568 bindtextdomain(PACKAGE, LOCALEDIR);
1569 bind_textdomain_codeset(PACKAGE, "UTF-8");
1570 textdomain(PACKAGE);
1577 //add_pixmap_directory (PACKAGE_DATA_DIR "/" PACKAGE "/pixmaps");
1578 //add_pixmap_directory (PACKAGE_SOURCE_DIR "/pixmaps");
1580 /* Determine GUI path */
1581 env = getenv(SRCTREE);
1583 glade_file = g_strconcat(env, "/scripts/kconfig/gconf.glade", NULL);
1584 else if (av[0][0] == '/')
1585 glade_file = g_strconcat(av[0], ".glade", NULL);
1587 glade_file = g_strconcat(g_get_current_dir(), "/", av[0], ".glade", NULL);
1589 /* Load the interface and connect signals */
1590 init_main_window(glade_file);
1596 if (ac > 1 && av[1][0] == '-') {
1603 printf("%s <config>\n", av[0]);
1611 fixup_rootmenu(&rootmenu);
1614 switch (view_mode) {
1616 display_tree_part();
1622 display_tree(&rootmenu);
1631 static void conf_changed(void)
1633 bool changed = conf_get_changed();
1634 gtk_widget_set_sensitive(save_btn, changed);
1635 gtk_widget_set_sensitive(save_menu_item, changed);