1 /* Hey EMACS -*- linux-c -*- */
4 * Copyright (C) 2002-2003 Romain Lievin <roms@tilp.info>
5 * Released under the terms of the GNU GPL v2.0.
16 #include <glade/glade.h>
19 #include <gdk/gdkkeysyms.h>
30 SINGLE_VIEW, SPLIT_VIEW, FULL_VIEW
33 static gint view_mode = FULL_VIEW;
34 static gboolean show_name = TRUE;
35 static gboolean show_range = TRUE;
36 static gboolean show_value = TRUE;
37 static gboolean show_all = FALSE;
38 static gboolean show_debug = FALSE;
39 static gboolean resizeable = FALSE;
41 GtkWidget *main_wnd = NULL;
42 GtkWidget *tree1_w = NULL; // left frame
43 GtkWidget *tree2_w = NULL; // right frame
44 GtkWidget *text_w = NULL;
45 GtkWidget *hpaned = NULL;
46 GtkWidget *vpaned = NULL;
47 GtkWidget *back_btn = NULL;
48 GtkWidget *save_btn = NULL;
49 GtkWidget *save_menu_item = NULL;
51 GtkTextTag *tag1, *tag2;
54 GtkTreeStore *tree1, *tree2, *tree;
55 GtkTreeModel *model1, *model2;
56 static GtkTreeIter *parents[256];
59 static struct menu *current; // current node for SINGLE view
60 static struct menu *browsed; // browsed node for SPLIT view
63 COL_OPTION, COL_NAME, COL_NO, COL_MOD, COL_YES, COL_VALUE,
64 COL_MENU, COL_COLOR, COL_EDIT, COL_PIXBUF,
65 COL_PIXVIS, COL_BTNVIS, COL_BTNACT, COL_BTNINC, COL_BTNRAD,
69 static void display_list(void);
70 static void display_tree(struct menu *menu);
71 static void display_tree_part(void);
72 static void update_tree(struct menu *src, GtkTreeIter * dst);
73 static void set_node(GtkTreeIter * node, struct menu *menu, gchar ** row);
74 static gchar **fill_row(struct menu *menu);
75 static void conf_changed(void);
77 /* Helping/Debugging Functions */
80 const char *dbg_print_stype(int val)
87 strcpy(buf, "unknown");
89 strcpy(buf, "boolean");
90 if (val == S_TRISTATE)
91 strcpy(buf, "tristate");
97 strcpy(buf, "string");
108 const char *dbg_print_flags(int val)
110 static char buf[256];
114 if (val & SYMBOL_CONST)
115 strcat(buf, "const/");
116 if (val & SYMBOL_CHECK)
117 strcat(buf, "check/");
118 if (val & SYMBOL_CHOICE)
119 strcat(buf, "choice/");
120 if (val & SYMBOL_CHOICEVAL)
121 strcat(buf, "choiceval/");
122 if (val & SYMBOL_VALID)
123 strcat(buf, "valid/");
124 if (val & SYMBOL_OPTIONAL)
125 strcat(buf, "optional/");
126 if (val & SYMBOL_WRITE)
127 strcat(buf, "write/");
128 if (val & SYMBOL_CHANGED)
129 strcat(buf, "changed/");
130 if (val & SYMBOL_AUTO)
131 strcat(buf, "auto/");
133 buf[strlen(buf) - 1] = '\0';
141 const char *dbg_print_ptype(int val)
143 static char buf[256];
147 if (val == P_UNKNOWN)
148 strcpy(buf, "unknown");
150 strcpy(buf, "prompt");
151 if (val == P_COMMENT)
152 strcpy(buf, "comment");
155 if (val == P_DEFAULT)
156 strcpy(buf, "default");
158 strcpy(buf, "choice");
168 void replace_button_icon(GladeXML * xml, GdkDrawable * window,
169 GtkStyle * style, gchar * btn_name, gchar ** xpm)
173 GtkToolButton *button;
176 pixmap = gdk_pixmap_create_from_xpm_d(window, &mask,
177 &style->bg[GTK_STATE_NORMAL],
180 button = GTK_TOOL_BUTTON(glade_xml_get_widget(xml, btn_name));
181 image = gtk_image_new_from_pixmap(pixmap, mask);
182 gtk_widget_show(image);
183 gtk_tool_button_set_icon_widget(button, image);
186 /* Main Window Initialization */
187 void init_main_window(const gchar * glade_file)
191 GtkTextBuffer *txtbuf;
195 xml = glade_xml_new(glade_file, "window1", NULL);
197 g_error(_("GUI loading failed !\n"));
198 glade_xml_signal_autoconnect(xml);
200 main_wnd = glade_xml_get_widget(xml, "window1");
201 hpaned = glade_xml_get_widget(xml, "hpaned1");
202 vpaned = glade_xml_get_widget(xml, "vpaned1");
203 tree1_w = glade_xml_get_widget(xml, "treeview1");
204 tree2_w = glade_xml_get_widget(xml, "treeview2");
205 text_w = glade_xml_get_widget(xml, "textview3");
207 back_btn = glade_xml_get_widget(xml, "button1");
208 gtk_widget_set_sensitive(back_btn, FALSE);
210 widget = glade_xml_get_widget(xml, "show_name1");
211 gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget,
214 widget = glade_xml_get_widget(xml, "show_range1");
215 gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget,
218 widget = glade_xml_get_widget(xml, "show_data1");
219 gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget,
222 save_btn = glade_xml_get_widget(xml, "button3");
223 save_menu_item = glade_xml_get_widget(xml, "save1");
224 conf_set_changed_callback(conf_changed);
226 style = gtk_widget_get_style(main_wnd);
227 widget = glade_xml_get_widget(xml, "toolbar1");
229 #if 0 /* Use stock Gtk icons instead */
230 replace_button_icon(xml, main_wnd->window, style,
231 "button1", (gchar **) xpm_back);
232 replace_button_icon(xml, main_wnd->window, style,
233 "button2", (gchar **) xpm_load);
234 replace_button_icon(xml, main_wnd->window, style,
235 "button3", (gchar **) xpm_save);
237 replace_button_icon(xml, main_wnd->window, style,
238 "button4", (gchar **) xpm_single_view);
239 replace_button_icon(xml, main_wnd->window, style,
240 "button5", (gchar **) xpm_split_view);
241 replace_button_icon(xml, main_wnd->window, style,
242 "button6", (gchar **) xpm_tree_view);
247 widget = glade_xml_get_widget(xml, "button4");
248 g_signal_emit_by_name(widget, "clicked");
251 widget = glade_xml_get_widget(xml, "button5");
252 g_signal_emit_by_name(widget, "clicked");
255 widget = glade_xml_get_widget(xml, "button6");
256 g_signal_emit_by_name(widget, "clicked");
260 txtbuf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w));
261 tag1 = gtk_text_buffer_create_tag(txtbuf, "mytag1",
263 "weight", PANGO_WEIGHT_BOLD,
265 tag2 = gtk_text_buffer_create_tag(txtbuf, "mytag2",
266 /*"style", PANGO_STYLE_OBLIQUE, */
269 sprintf(title, _("Linux Kernel v%s Configuration"),
270 getenv("KERNELVERSION"));
271 gtk_window_set_title(GTK_WINDOW(main_wnd), title);
273 gtk_widget_show(main_wnd);
276 void init_tree_model(void)
280 tree = tree2 = gtk_tree_store_new(COL_NUMBER,
281 G_TYPE_STRING, G_TYPE_STRING,
282 G_TYPE_STRING, G_TYPE_STRING,
283 G_TYPE_STRING, G_TYPE_STRING,
284 G_TYPE_POINTER, GDK_TYPE_COLOR,
285 G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF,
286 G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
287 G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
289 model2 = GTK_TREE_MODEL(tree2);
291 for (parents[0] = NULL, i = 1; i < 256; i++)
292 parents[i] = (GtkTreeIter *) g_malloc(sizeof(GtkTreeIter));
294 tree1 = gtk_tree_store_new(COL_NUMBER,
295 G_TYPE_STRING, G_TYPE_STRING,
296 G_TYPE_STRING, G_TYPE_STRING,
297 G_TYPE_STRING, G_TYPE_STRING,
298 G_TYPE_POINTER, GDK_TYPE_COLOR,
299 G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF,
300 G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
301 G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
303 model1 = GTK_TREE_MODEL(tree1);
306 void init_left_tree(void)
308 GtkTreeView *view = GTK_TREE_VIEW(tree1_w);
309 GtkCellRenderer *renderer;
310 GtkTreeSelection *sel;
311 GtkTreeViewColumn *column;
313 gtk_tree_view_set_model(view, model1);
314 gtk_tree_view_set_headers_visible(view, TRUE);
315 gtk_tree_view_set_rules_hint(view, FALSE);
317 column = gtk_tree_view_column_new();
318 gtk_tree_view_append_column(view, column);
319 gtk_tree_view_column_set_title(column, _("Options"));
321 renderer = gtk_cell_renderer_toggle_new();
322 gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
324 gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
326 "active", COL_BTNACT,
327 "inconsistent", COL_BTNINC,
328 "visible", COL_BTNVIS,
329 "radio", COL_BTNRAD, NULL);
330 renderer = gtk_cell_renderer_text_new();
331 gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
333 gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
339 sel = gtk_tree_view_get_selection(view);
340 gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
341 gtk_widget_realize(tree1_w);
344 static void renderer_edited(GtkCellRendererText * cell,
345 const gchar * path_string,
346 const gchar * new_text, gpointer user_data);
347 static void renderer_toggled(GtkCellRendererToggle * cellrenderertoggle,
348 gchar * arg1, gpointer user_data);
350 void init_right_tree(void)
352 GtkTreeView *view = GTK_TREE_VIEW(tree2_w);
353 GtkCellRenderer *renderer;
354 GtkTreeSelection *sel;
355 GtkTreeViewColumn *column;
358 gtk_tree_view_set_model(view, model2);
359 gtk_tree_view_set_headers_visible(view, TRUE);
360 gtk_tree_view_set_rules_hint(view, FALSE);
362 column = gtk_tree_view_column_new();
363 gtk_tree_view_append_column(view, column);
364 gtk_tree_view_column_set_title(column, _("Options"));
366 renderer = gtk_cell_renderer_pixbuf_new();
367 gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
369 gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
371 "pixbuf", COL_PIXBUF,
372 "visible", COL_PIXVIS, NULL);
373 renderer = gtk_cell_renderer_toggle_new();
374 gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
376 gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
378 "active", COL_BTNACT,
379 "inconsistent", COL_BTNINC,
380 "visible", COL_BTNVIS,
381 "radio", COL_BTNRAD, NULL);
382 /*g_signal_connect(G_OBJECT(renderer), "toggled",
383 G_CALLBACK(renderer_toggled), NULL); */
384 renderer = gtk_cell_renderer_text_new();
385 gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
387 gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
393 renderer = gtk_cell_renderer_text_new();
394 gtk_tree_view_insert_column_with_attributes(view, -1,
399 renderer = gtk_cell_renderer_text_new();
400 gtk_tree_view_insert_column_with_attributes(view, -1,
405 renderer = gtk_cell_renderer_text_new();
406 gtk_tree_view_insert_column_with_attributes(view, -1,
411 renderer = gtk_cell_renderer_text_new();
412 gtk_tree_view_insert_column_with_attributes(view, -1,
417 renderer = gtk_cell_renderer_text_new();
418 gtk_tree_view_insert_column_with_attributes(view, -1,
419 _("Value"), renderer,
425 g_signal_connect(G_OBJECT(renderer), "edited",
426 G_CALLBACK(renderer_edited), NULL);
428 column = gtk_tree_view_get_column(view, COL_NAME);
429 gtk_tree_view_column_set_visible(column, show_name);
430 column = gtk_tree_view_get_column(view, COL_NO);
431 gtk_tree_view_column_set_visible(column, show_range);
432 column = gtk_tree_view_get_column(view, COL_MOD);
433 gtk_tree_view_column_set_visible(column, show_range);
434 column = gtk_tree_view_get_column(view, COL_YES);
435 gtk_tree_view_column_set_visible(column, show_range);
436 column = gtk_tree_view_get_column(view, COL_VALUE);
437 gtk_tree_view_column_set_visible(column, show_value);
440 for (i = 0; i < COL_VALUE; i++) {
441 column = gtk_tree_view_get_column(view, i);
442 gtk_tree_view_column_set_resizable(column, TRUE);
446 sel = gtk_tree_view_get_selection(view);
447 gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
451 /* Utility Functions */
454 static void text_insert_help(struct menu *menu)
456 GtkTextBuffer *buffer;
457 GtkTextIter start, end;
458 const char *prompt = menu_get_prompt(menu);
462 help = _(menu_get_help(menu));
464 if (menu->sym && menu->sym->name)
465 name = g_strdup_printf(_(menu->sym->name));
469 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w));
470 gtk_text_buffer_get_bounds(buffer, &start, &end);
471 gtk_text_buffer_delete(buffer, &start, &end);
472 gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_w), 15);
474 gtk_text_buffer_get_end_iter(buffer, &end);
475 gtk_text_buffer_insert_with_tags(buffer, &end, prompt, -1, tag1,
477 gtk_text_buffer_insert_at_cursor(buffer, " ", 1);
478 gtk_text_buffer_get_end_iter(buffer, &end);
479 gtk_text_buffer_insert_with_tags(buffer, &end, name, -1, tag1,
481 gtk_text_buffer_insert_at_cursor(buffer, "\n\n", 2);
482 gtk_text_buffer_get_end_iter(buffer, &end);
483 gtk_text_buffer_insert_with_tags(buffer, &end, help, -1, tag2,
488 static void text_insert_msg(const char *title, const char *message)
490 GtkTextBuffer *buffer;
491 GtkTextIter start, end;
492 const char *msg = message;
494 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w));
495 gtk_text_buffer_get_bounds(buffer, &start, &end);
496 gtk_text_buffer_delete(buffer, &start, &end);
497 gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_w), 15);
499 gtk_text_buffer_get_end_iter(buffer, &end);
500 gtk_text_buffer_insert_with_tags(buffer, &end, title, -1, tag1,
502 gtk_text_buffer_insert_at_cursor(buffer, "\n\n", 2);
503 gtk_text_buffer_get_end_iter(buffer, &end);
504 gtk_text_buffer_insert_with_tags(buffer, &end, msg, -1, tag2,
509 /* Main Windows Callbacks */
511 void on_save_activate(GtkMenuItem * menuitem, gpointer user_data);
512 gboolean on_window1_delete_event(GtkWidget * widget, GdkEvent * event,
515 GtkWidget *dialog, *label;
518 if (!conf_get_changed())
521 dialog = gtk_dialog_new_with_buttons(_("Warning !"),
522 GTK_WINDOW(main_wnd),
525 GTK_DIALOG_DESTROY_WITH_PARENT),
531 GTK_RESPONSE_CANCEL, NULL);
532 gtk_dialog_set_default_response(GTK_DIALOG(dialog),
533 GTK_RESPONSE_CANCEL);
535 label = gtk_label_new(_("\nSave configuration ?\n"));
536 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), label);
537 gtk_widget_show(label);
539 result = gtk_dialog_run(GTK_DIALOG(dialog));
541 case GTK_RESPONSE_YES:
542 on_save_activate(NULL, NULL);
544 case GTK_RESPONSE_NO:
546 case GTK_RESPONSE_CANCEL:
547 case GTK_RESPONSE_DELETE_EVENT:
549 gtk_widget_destroy(dialog);
557 void on_window1_destroy(GtkObject * object, gpointer user_data)
564 on_window1_size_request(GtkWidget * widget,
565 GtkRequisition * requisition, gpointer user_data)
570 if (widget->window == NULL)
571 gtk_window_get_default_size(GTK_WINDOW(main_wnd), &w, &h);
573 gdk_window_get_size(widget->window, &w, &h);
579 gtk_paned_set_position(GTK_PANED(vpaned), 2 * h / 3);
583 /* Menu & Toolbar Callbacks */
587 load_filename(GtkFileSelection * file_selector, gpointer user_data)
591 fn = gtk_file_selection_get_filename(GTK_FILE_SELECTION
595 text_insert_msg(_("Error"), _("Unable to load configuration !"));
597 display_tree(&rootmenu);
600 void on_load1_activate(GtkMenuItem * menuitem, gpointer user_data)
604 fs = gtk_file_selection_new(_("Load file..."));
605 g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs)->ok_button),
607 G_CALLBACK(load_filename), (gpointer) fs);
608 g_signal_connect_swapped(GTK_OBJECT
609 (GTK_FILE_SELECTION(fs)->ok_button),
610 "clicked", G_CALLBACK(gtk_widget_destroy),
612 g_signal_connect_swapped(GTK_OBJECT
613 (GTK_FILE_SELECTION(fs)->cancel_button),
614 "clicked", G_CALLBACK(gtk_widget_destroy),
620 void on_save_activate(GtkMenuItem * menuitem, gpointer user_data)
622 if (conf_write(NULL))
623 text_insert_msg(_("Error"), _("Unable to save configuration !"));
628 store_filename(GtkFileSelection * file_selector, gpointer user_data)
632 fn = gtk_file_selection_get_filename(GTK_FILE_SELECTION
636 text_insert_msg(_("Error"), _("Unable to save configuration !"));
638 gtk_widget_destroy(GTK_WIDGET(user_data));
641 void on_save_as1_activate(GtkMenuItem * menuitem, gpointer user_data)
645 fs = gtk_file_selection_new(_("Save file as..."));
646 g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs)->ok_button),
648 G_CALLBACK(store_filename), (gpointer) fs);
649 g_signal_connect_swapped(GTK_OBJECT
650 (GTK_FILE_SELECTION(fs)->ok_button),
651 "clicked", G_CALLBACK(gtk_widget_destroy),
653 g_signal_connect_swapped(GTK_OBJECT
654 (GTK_FILE_SELECTION(fs)->cancel_button),
655 "clicked", G_CALLBACK(gtk_widget_destroy),
661 void on_quit1_activate(GtkMenuItem * menuitem, gpointer user_data)
663 if (!on_window1_delete_event(NULL, NULL, NULL))
664 gtk_widget_destroy(GTK_WIDGET(main_wnd));
668 void on_show_name1_activate(GtkMenuItem * menuitem, gpointer user_data)
670 GtkTreeViewColumn *col;
672 show_name = GTK_CHECK_MENU_ITEM(menuitem)->active;
673 col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_NAME);
675 gtk_tree_view_column_set_visible(col, show_name);
679 void on_show_range1_activate(GtkMenuItem * menuitem, gpointer user_data)
681 GtkTreeViewColumn *col;
683 show_range = GTK_CHECK_MENU_ITEM(menuitem)->active;
684 col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_NO);
686 gtk_tree_view_column_set_visible(col, show_range);
687 col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_MOD);
689 gtk_tree_view_column_set_visible(col, show_range);
690 col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_YES);
692 gtk_tree_view_column_set_visible(col, show_range);
697 void on_show_data1_activate(GtkMenuItem * menuitem, gpointer user_data)
699 GtkTreeViewColumn *col;
701 show_value = GTK_CHECK_MENU_ITEM(menuitem)->active;
702 col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_VALUE);
704 gtk_tree_view_column_set_visible(col, show_value);
709 on_show_all_options1_activate(GtkMenuItem * menuitem, gpointer user_data)
711 show_all = GTK_CHECK_MENU_ITEM(menuitem)->active;
713 gtk_tree_store_clear(tree2);
714 display_tree(&rootmenu); // instead of update_tree to speed-up
719 on_show_debug_info1_activate(GtkMenuItem * menuitem, gpointer user_data)
721 show_debug = GTK_CHECK_MENU_ITEM(menuitem)->active;
722 update_tree(&rootmenu, NULL);
726 void on_introduction1_activate(GtkMenuItem * menuitem, gpointer user_data)
729 const gchar *intro_text = _(
730 "Welcome to gkc, the GTK+ graphical kernel configuration tool\n"
732 "For each option, a blank box indicates the feature is disabled, a\n"
733 "check indicates it is enabled, and a dot indicates that it is to\n"
734 "be compiled as a module. Clicking on the box will cycle through the three states.\n"
736 "If you do not see an option (e.g., a device driver) that you\n"
737 "believe should be present, try turning on Show All Options\n"
738 "under the Options menu.\n"
739 "Although there is no cross reference yet to help you figure out\n"
740 "what other options must be enabled to support the option you\n"
741 "are interested in, you can still view the help of a grayed-out\n"
744 "Toggling Show Debug Info under the Options menu will show \n"
745 "the dependencies, which you can then match by examining other options.");
747 dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
748 GTK_DIALOG_DESTROY_WITH_PARENT,
750 GTK_BUTTONS_CLOSE, intro_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_about1_activate(GtkMenuItem * menuitem, gpointer user_data)
761 const gchar *about_text =
762 _("gkc is copyright (c) 2002 Romain Lievin <roms@lpg.ticalc.org>.\n"
763 "Based on the source code from Roman Zippel.\n");
765 dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
766 GTK_DIALOG_DESTROY_WITH_PARENT,
768 GTK_BUTTONS_CLOSE, about_text);
769 g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
770 G_CALLBACK(gtk_widget_destroy),
772 gtk_widget_show_all(dialog);
776 void on_license1_activate(GtkMenuItem * menuitem, gpointer user_data)
779 const gchar *license_text =
780 _("gkc is released under the terms of the GNU GPL v2.\n"
781 "For more information, please see the source code or\n"
782 "visit http://www.fsf.org/licenses/licenses.html\n");
784 dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
785 GTK_DIALOG_DESTROY_WITH_PARENT,
787 GTK_BUTTONS_CLOSE, license_text);
788 g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
789 G_CALLBACK(gtk_widget_destroy),
791 gtk_widget_show_all(dialog);
795 void on_back_clicked(GtkButton * button, gpointer user_data)
797 enum prop_type ptype;
799 current = current->parent;
800 ptype = current->prompt ? current->prompt->type : P_UNKNOWN;
802 current = current->parent;
805 if (current == &rootmenu)
806 gtk_widget_set_sensitive(back_btn, FALSE);
810 void on_load_clicked(GtkButton * button, gpointer user_data)
812 on_load1_activate(NULL, user_data);
816 void on_single_clicked(GtkButton * button, gpointer user_data)
818 view_mode = SINGLE_VIEW;
819 gtk_paned_set_position(GTK_PANED(hpaned), 0);
820 gtk_widget_hide(tree1_w);
826 void on_split_clicked(GtkButton * button, gpointer user_data)
829 view_mode = SPLIT_VIEW;
830 gtk_widget_show(tree1_w);
831 gtk_window_get_default_size(GTK_WINDOW(main_wnd), &w, &h);
832 gtk_paned_set_position(GTK_PANED(hpaned), w / 2);
834 gtk_tree_store_clear(tree2);
837 /* Disable back btn, like in full mode. */
838 gtk_widget_set_sensitive(back_btn, FALSE);
842 void on_full_clicked(GtkButton * button, gpointer user_data)
844 view_mode = FULL_VIEW;
845 gtk_paned_set_position(GTK_PANED(hpaned), 0);
846 gtk_widget_hide(tree1_w);
848 gtk_tree_store_clear(tree2);
849 display_tree(&rootmenu);
850 gtk_widget_set_sensitive(back_btn, FALSE);
854 void on_collapse_clicked(GtkButton * button, gpointer user_data)
856 gtk_tree_view_collapse_all(GTK_TREE_VIEW(tree2_w));
860 void on_expand_clicked(GtkButton * button, gpointer user_data)
862 gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w));
866 /* CTree Callbacks */
868 /* Change hex/int/string value in the cell */
869 static void renderer_edited(GtkCellRendererText * cell,
870 const gchar * path_string,
871 const gchar * new_text, gpointer user_data)
873 GtkTreePath *path = gtk_tree_path_new_from_string(path_string);
875 const char *old_def, *new_def;
879 if (!gtk_tree_model_get_iter(model2, &iter, path))
882 gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
885 gtk_tree_model_get(model2, &iter, COL_VALUE, &old_def, -1);
888 sym_set_string_value(sym, new_def);
890 update_tree(&rootmenu, NULL);
892 gtk_tree_path_free(path);
895 /* Change the value of a symbol and update the tree */
896 static void change_sym_value(struct menu *menu, gint col)
898 struct symbol *sym = menu->sym;
899 tristate oldval, newval;
906 else if (col == COL_MOD)
908 else if (col == COL_YES)
913 switch (sym_get_type(sym)) {
916 oldval = sym_get_tristate_value(sym);
917 if (!sym_tristate_within_range(sym, newval))
919 sym_set_tristate_value(sym, newval);
920 if (view_mode == FULL_VIEW)
921 update_tree(&rootmenu, NULL);
922 else if (view_mode == SPLIT_VIEW) {
923 update_tree(browsed, NULL);
926 else if (view_mode == SINGLE_VIEW)
927 display_tree_part(); //fixme: keep exp/coll
937 static void toggle_sym_value(struct menu *menu)
942 sym_toggle_tristate_value(menu->sym);
943 if (view_mode == FULL_VIEW)
944 update_tree(&rootmenu, NULL);
945 else if (view_mode == SPLIT_VIEW) {
946 update_tree(browsed, NULL);
949 else if (view_mode == SINGLE_VIEW)
950 display_tree_part(); //fixme: keep exp/coll
953 static void renderer_toggled(GtkCellRendererToggle * cell,
954 gchar * path_string, gpointer user_data)
956 GtkTreePath *path, *sel_path = NULL;
957 GtkTreeIter iter, sel_iter;
958 GtkTreeSelection *sel;
961 path = gtk_tree_path_new_from_string(path_string);
962 if (!gtk_tree_model_get_iter(model2, &iter, path))
965 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree2_w));
966 if (gtk_tree_selection_get_selected(sel, NULL, &sel_iter))
967 sel_path = gtk_tree_model_get_path(model2, &sel_iter);
970 if (gtk_tree_path_compare(path, sel_path))
973 gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
974 toggle_sym_value(menu);
977 gtk_tree_path_free(sel_path);
979 gtk_tree_path_free(path);
982 static gint column2index(GtkTreeViewColumn * column)
986 for (i = 0; i < COL_NUMBER; i++) {
987 GtkTreeViewColumn *col;
989 col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), i);
998 /* User click: update choice (full) or goes down (single) */
1000 on_treeview2_button_press_event(GtkWidget * widget,
1001 GdkEventButton * event, gpointer user_data)
1003 GtkTreeView *view = GTK_TREE_VIEW(widget);
1005 GtkTreeViewColumn *column;
1010 #if GTK_CHECK_VERSION(2,1,4) // bug in ctree with earlier version of GTK
1011 gint tx = (gint) event->x;
1012 gint ty = (gint) event->y;
1015 gtk_tree_view_get_path_at_pos(view, tx, ty, &path, &column, &cx,
1018 gtk_tree_view_get_cursor(view, &path, &column);
1023 if (!gtk_tree_model_get_iter(model2, &iter, path))
1025 gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
1027 col = column2index(column);
1028 if (event->type == GDK_2BUTTON_PRESS) {
1029 enum prop_type ptype;
1030 ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
1032 if (ptype == P_MENU && view_mode != FULL_VIEW && col == COL_OPTION) {
1033 // goes down into menu
1035 display_tree_part();
1036 gtk_widget_set_sensitive(back_btn, TRUE);
1037 } else if ((col == COL_OPTION)) {
1038 toggle_sym_value(menu);
1039 gtk_tree_view_expand_row(view, path, TRUE);
1042 if (col == COL_VALUE) {
1043 toggle_sym_value(menu);
1044 gtk_tree_view_expand_row(view, path, TRUE);
1045 } else if (col == COL_NO || col == COL_MOD
1046 || col == COL_YES) {
1047 change_sym_value(menu, col);
1048 gtk_tree_view_expand_row(view, path, TRUE);
1055 /* Key pressed: update choice */
1057 on_treeview2_key_press_event(GtkWidget * widget,
1058 GdkEventKey * event, gpointer user_data)
1060 GtkTreeView *view = GTK_TREE_VIEW(widget);
1062 GtkTreeViewColumn *column;
1067 gtk_tree_view_get_cursor(view, &path, &column);
1071 if (event->keyval == GDK_space) {
1072 if (gtk_tree_view_row_expanded(view, path))
1073 gtk_tree_view_collapse_row(view, path);
1075 gtk_tree_view_expand_row(view, path, FALSE);
1078 if (event->keyval == GDK_KP_Enter) {
1080 if (widget == tree1_w)
1083 gtk_tree_model_get_iter(model2, &iter, path);
1084 gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
1086 if (!strcasecmp(event->string, "n"))
1088 else if (!strcasecmp(event->string, "m"))
1090 else if (!strcasecmp(event->string, "y"))
1094 change_sym_value(menu, col);
1100 /* Row selection changed: update help */
1102 on_treeview2_cursor_changed(GtkTreeView * treeview, gpointer user_data)
1104 GtkTreeSelection *selection;
1108 selection = gtk_tree_view_get_selection(treeview);
1109 if (gtk_tree_selection_get_selected(selection, &model2, &iter)) {
1110 gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
1111 text_insert_help(menu);
1116 /* User click: display sub-tree in the right frame. */
1118 on_treeview1_button_press_event(GtkWidget * widget,
1119 GdkEventButton * event, gpointer user_data)
1121 GtkTreeView *view = GTK_TREE_VIEW(widget);
1123 GtkTreeViewColumn *column;
1127 gint tx = (gint) event->x;
1128 gint ty = (gint) event->y;
1131 gtk_tree_view_get_path_at_pos(view, tx, ty, &path, &column, &cx,
1136 gtk_tree_model_get_iter(model1, &iter, path);
1137 gtk_tree_model_get(model1, &iter, COL_MENU, &menu, -1);
1139 if (event->type == GDK_2BUTTON_PRESS) {
1140 toggle_sym_value(menu);
1142 display_tree_part();
1145 display_tree_part();
1148 gtk_widget_realize(tree2_w);
1149 gtk_tree_view_set_cursor(view, path, NULL, FALSE);
1150 gtk_widget_grab_focus(tree2_w);
1156 /* Fill a row of strings */
1157 static gchar **fill_row(struct menu *menu)
1159 static gchar *row[COL_NUMBER];
1160 struct symbol *sym = menu->sym;
1164 enum prop_type ptype;
1167 for (i = COL_OPTION; i <= COL_COLOR; i++)
1169 bzero(row, sizeof(row));
1172 g_strdup_printf("%s %s", menu_get_prompt(menu),
1173 sym && sym_has_value(sym) ? "(NEW)" : "");
1175 if (show_all && !menu_is_visible(menu))
1176 row[COL_COLOR] = g_strdup("DarkGray");
1178 row[COL_COLOR] = g_strdup("Black");
1180 ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
1183 row[COL_PIXBUF] = (gchar *) xpm_menu;
1184 if (view_mode == SINGLE_VIEW)
1185 row[COL_PIXVIS] = GINT_TO_POINTER(TRUE);
1186 row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
1189 row[COL_PIXBUF] = (gchar *) xpm_void;
1190 row[COL_PIXVIS] = GINT_TO_POINTER(FALSE);
1191 row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
1194 row[COL_PIXBUF] = (gchar *) xpm_void;
1195 row[COL_PIXVIS] = GINT_TO_POINTER(FALSE);
1196 row[COL_BTNVIS] = GINT_TO_POINTER(TRUE);
1202 row[COL_NAME] = g_strdup(sym->name);
1204 sym_calc_value(sym);
1205 sym->flags &= ~SYMBOL_CHANGED;
1207 if (sym_is_choice(sym)) { // parse childs for getting final value
1209 struct symbol *def_sym = sym_get_choice_value(sym);
1210 struct menu *def_menu = NULL;
1212 row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
1214 for (child = menu->list; child; child = child->next) {
1215 if (menu_is_visible(child)
1216 && child->sym == def_sym)
1222 g_strdup(menu_get_prompt(def_menu));
1224 if (sym->flags & SYMBOL_CHOICEVAL)
1225 row[COL_BTNRAD] = GINT_TO_POINTER(TRUE);
1227 stype = sym_get_type(sym);
1230 if (GPOINTER_TO_INT(row[COL_PIXVIS]) == FALSE)
1231 row[COL_BTNVIS] = GINT_TO_POINTER(TRUE);
1232 if (sym_is_choice(sym))
1235 val = sym_get_tristate_value(sym);
1238 row[COL_NO] = g_strdup("N");
1239 row[COL_VALUE] = g_strdup("N");
1240 row[COL_BTNACT] = GINT_TO_POINTER(FALSE);
1241 row[COL_BTNINC] = GINT_TO_POINTER(FALSE);
1244 row[COL_MOD] = g_strdup("M");
1245 row[COL_VALUE] = g_strdup("M");
1246 row[COL_BTNINC] = GINT_TO_POINTER(TRUE);
1249 row[COL_YES] = g_strdup("Y");
1250 row[COL_VALUE] = g_strdup("Y");
1251 row[COL_BTNACT] = GINT_TO_POINTER(TRUE);
1252 row[COL_BTNINC] = GINT_TO_POINTER(FALSE);
1256 if (val != no && sym_tristate_within_range(sym, no))
1257 row[COL_NO] = g_strdup("_");
1258 if (val != mod && sym_tristate_within_range(sym, mod))
1259 row[COL_MOD] = g_strdup("_");
1260 if (val != yes && sym_tristate_within_range(sym, yes))
1261 row[COL_YES] = g_strdup("_");
1266 def = sym_get_string_value(sym);
1267 row[COL_VALUE] = g_strdup(def);
1268 row[COL_EDIT] = GINT_TO_POINTER(TRUE);
1269 row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
1277 /* Set the node content with a row of strings */
1278 static void set_node(GtkTreeIter * node, struct menu *menu, gchar ** row)
1284 pix = gdk_pixbuf_new_from_xpm_data((const char **)
1287 gdk_color_parse(row[COL_COLOR], &color);
1288 gdk_colormap_alloc_colors(gdk_colormap_get_system(), &color, 1,
1289 FALSE, FALSE, &success);
1291 gtk_tree_store_set(tree, node,
1292 COL_OPTION, row[COL_OPTION],
1293 COL_NAME, row[COL_NAME],
1294 COL_NO, row[COL_NO],
1295 COL_MOD, row[COL_MOD],
1296 COL_YES, row[COL_YES],
1297 COL_VALUE, row[COL_VALUE],
1298 COL_MENU, (gpointer) menu,
1300 COL_EDIT, GPOINTER_TO_INT(row[COL_EDIT]),
1302 COL_PIXVIS, GPOINTER_TO_INT(row[COL_PIXVIS]),
1303 COL_BTNVIS, GPOINTER_TO_INT(row[COL_BTNVIS]),
1304 COL_BTNACT, GPOINTER_TO_INT(row[COL_BTNACT]),
1305 COL_BTNINC, GPOINTER_TO_INT(row[COL_BTNINC]),
1306 COL_BTNRAD, GPOINTER_TO_INT(row[COL_BTNRAD]),
1309 g_object_unref(pix);
1313 /* Add a node to the tree */
1314 static void place_node(struct menu *menu, char **row)
1316 GtkTreeIter *parent = parents[indent - 1];
1317 GtkTreeIter *node = parents[indent];
1319 gtk_tree_store_append(tree, node, parent);
1320 set_node(node, menu, row);
1324 /* Find a node in the GTK+ tree */
1325 static GtkTreeIter found;
1328 * Find a menu in the GtkTree starting at parent.
1330 GtkTreeIter *gtktree_iter_find_node(GtkTreeIter * parent,
1331 struct menu *tofind)
1334 GtkTreeIter *child = &iter;
1338 valid = gtk_tree_model_iter_children(model2, child, parent);
1342 gtk_tree_model_get(model2, child, 6, &menu, -1);
1344 if (menu == tofind) {
1345 memcpy(&found, child, sizeof(GtkTreeIter));
1349 ret = gtktree_iter_find_node(child, tofind);
1353 valid = gtk_tree_model_iter_next(model2, child);
1361 * Update the tree by adding/removing entries
1362 * Does not change other nodes
1364 static void update_tree(struct menu *src, GtkTreeIter * dst)
1366 struct menu *child1;
1367 GtkTreeIter iter, tmp;
1368 GtkTreeIter *child2 = &iter;
1370 GtkTreeIter *sibling;
1372 struct property *prop;
1373 struct menu *menu1, *menu2;
1375 if (src == &rootmenu)
1378 valid = gtk_tree_model_iter_children(model2, child2, dst);
1379 for (child1 = src->list; child1; child1 = child1->next) {
1381 prop = child1->prompt;
1387 gtk_tree_model_get(model2, child2, COL_MENU,
1390 menu2 = NULL; // force adding of a first child
1393 printf("%*c%s | %s\n", indent, ' ',
1394 menu1 ? menu_get_prompt(menu1) : "nil",
1395 menu2 ? menu_get_prompt(menu2) : "nil");
1398 if (!menu_is_visible(child1) && !show_all) { // remove node
1399 if (gtktree_iter_find_node(dst, menu1) != NULL) {
1400 memcpy(&tmp, child2, sizeof(GtkTreeIter));
1401 valid = gtk_tree_model_iter_next(model2,
1403 gtk_tree_store_remove(tree2, &tmp);
1405 return; // next parent
1407 goto reparse; // next child
1412 if (menu1 != menu2) {
1413 if (gtktree_iter_find_node(dst, menu1) == NULL) { // add node
1414 if (!valid && !menu2)
1418 gtk_tree_store_insert_before(tree2,
1421 set_node(child2, menu1, fill_row(menu1));
1424 } else { // remove node
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
1434 } else if (sym && (sym->flags & SYMBOL_CHANGED)) {
1435 set_node(child2, menu1, fill_row(menu1));
1439 update_tree(child1, child2);
1442 valid = gtk_tree_model_iter_next(model2, child2);
1447 /* Display the whole tree (single/split/full view) */
1448 static void display_tree(struct menu *menu)
1451 struct property *prop;
1453 enum prop_type ptype;
1455 if (menu == &rootmenu) {
1457 current = &rootmenu;
1460 for (child = menu->list; child; child = child->next) {
1461 prop = child->prompt;
1463 ptype = prop ? prop->type : P_UNKNOWN;
1466 sym->flags &= ~SYMBOL_CHANGED;
1468 if ((view_mode == SPLIT_VIEW)
1469 && !(child->flags & MENU_ROOT) && (tree == tree1))
1472 if ((view_mode == SPLIT_VIEW) && (child->flags & MENU_ROOT)
1476 if (menu_is_visible(child) || show_all)
1477 place_node(child, fill_row(child));
1479 printf("%*c%s: ", indent, ' ', menu_get_prompt(child));
1480 printf("%s", child->flags & MENU_ROOT ? "rootmenu | " : "");
1481 dbg_print_ptype(ptype);
1484 dbg_print_stype(sym->type);
1486 dbg_print_flags(sym->flags);
1491 if ((view_mode != FULL_VIEW) && (ptype == P_MENU)
1495 if (((menu != &rootmenu) && !(menu->flags & MENU_ROOT))
1496 || (view_mode == FULL_VIEW)
1497 || (view_mode == SPLIT_VIEW))*/
1498 if (((view_mode == SINGLE_VIEW) && (menu->flags & MENU_ROOT))
1499 || (view_mode == FULL_VIEW)
1500 || (view_mode == SPLIT_VIEW)) {
1502 display_tree(child);
1508 /* Display a part of the tree starting at current node (single/split view) */
1509 static void display_tree_part(void)
1512 gtk_tree_store_clear(tree2);
1513 if (view_mode == SINGLE_VIEW)
1514 display_tree(current);
1515 else if (view_mode == SPLIT_VIEW)
1516 display_tree(browsed);
1517 gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w));
1520 /* Display the list in the left frame (split view) */
1521 static void display_list(void)
1524 gtk_tree_store_clear(tree1);
1527 display_tree(&rootmenu);
1528 gtk_tree_view_expand_all(GTK_TREE_VIEW(tree1_w));
1532 void fixup_rootmenu(struct menu *menu)
1535 static int menu_cnt = 0;
1537 menu->flags |= MENU_ROOT;
1538 for (child = menu->list; child; child = child->next) {
1539 if (child->prompt && child->prompt->type == P_MENU) {
1541 fixup_rootmenu(child);
1543 } else if (!menu_cnt)
1544 fixup_rootmenu(child);
1550 int main(int ac, char *av[])
1556 #ifndef LKC_DIRECT_LINK
1560 bindtextdomain(PACKAGE, LOCALEDIR);
1561 bind_textdomain_codeset(PACKAGE, "UTF-8");
1562 textdomain(PACKAGE);
1569 //add_pixmap_directory (PACKAGE_DATA_DIR "/" PACKAGE "/pixmaps");
1570 //add_pixmap_directory (PACKAGE_SOURCE_DIR "/pixmaps");
1572 /* Determine GUI path */
1573 env = getenv(SRCTREE);
1575 glade_file = g_strconcat(env, "/scripts/kconfig/gconf.glade", NULL);
1576 else if (av[0][0] == '/')
1577 glade_file = g_strconcat(av[0], ".glade", NULL);
1579 glade_file = g_strconcat(g_get_current_dir(), "/", av[0], ".glade", NULL);
1581 /* Load the interface and connect signals */
1582 init_main_window(glade_file);
1588 if (ac > 1 && av[1][0] == '-') {
1595 printf("%s <config>\n", av[0]);
1603 fixup_rootmenu(&rootmenu);
1606 switch (view_mode) {
1608 display_tree_part();
1614 display_tree(&rootmenu);
1623 static void conf_changed(void)
1625 bool changed = conf_get_changed();
1626 gtk_widget_set_sensitive(save_btn, changed);
1627 gtk_widget_set_sensitive(save_menu_item, changed);