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 N_("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_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_NEW)
137 if (val & SYMBOL_AUTO)
138 strcat(buf, "auto/");
140 buf[strlen(buf) - 1] = '\0';
148 const char *dbg_print_ptype(int val)
150 static char buf[256];
154 if (val == P_UNKNOWN)
155 strcpy(buf, "unknown");
157 strcpy(buf, "prompt");
158 if (val == P_COMMENT)
159 strcpy(buf, "comment");
162 if (val == P_DEFAULT)
163 strcpy(buf, "default");
165 strcpy(buf, "choice");
175 void replace_button_icon(GladeXML * xml, GdkDrawable * window,
176 GtkStyle * style, gchar * btn_name, gchar ** xpm)
180 GtkToolButton *button;
183 pixmap = gdk_pixmap_create_from_xpm_d(window, &mask,
184 &style->bg[GTK_STATE_NORMAL],
187 button = GTK_TOOL_BUTTON(glade_xml_get_widget(xml, btn_name));
188 image = gtk_image_new_from_pixmap(pixmap, mask);
189 gtk_widget_show(image);
190 gtk_tool_button_set_icon_widget(button, image);
193 /* Main Window Initialization */
194 void init_main_window(const gchar * glade_file)
198 GtkTextBuffer *txtbuf;
202 xml = glade_xml_new(glade_file, "window1", NULL);
204 g_error(_("GUI loading failed !\n"));
205 glade_xml_signal_autoconnect(xml);
207 main_wnd = glade_xml_get_widget(xml, "window1");
208 hpaned = glade_xml_get_widget(xml, "hpaned1");
209 vpaned = glade_xml_get_widget(xml, "vpaned1");
210 tree1_w = glade_xml_get_widget(xml, "treeview1");
211 tree2_w = glade_xml_get_widget(xml, "treeview2");
212 text_w = glade_xml_get_widget(xml, "textview3");
214 back_btn = glade_xml_get_widget(xml, "button1");
215 gtk_widget_set_sensitive(back_btn, FALSE);
217 widget = glade_xml_get_widget(xml, "show_name1");
218 gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget,
221 widget = glade_xml_get_widget(xml, "show_range1");
222 gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget,
225 widget = glade_xml_get_widget(xml, "show_data1");
226 gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget,
229 style = gtk_widget_get_style(main_wnd);
230 widget = glade_xml_get_widget(xml, "toolbar1");
232 #if 0 /* Use stock Gtk icons instead */
233 replace_button_icon(xml, main_wnd->window, style,
234 "button1", (gchar **) xpm_back);
235 replace_button_icon(xml, main_wnd->window, style,
236 "button2", (gchar **) xpm_load);
237 replace_button_icon(xml, main_wnd->window, style,
238 "button3", (gchar **) xpm_save);
240 replace_button_icon(xml, main_wnd->window, style,
241 "button4", (gchar **) xpm_single_view);
242 replace_button_icon(xml, main_wnd->window, style,
243 "button5", (gchar **) xpm_split_view);
244 replace_button_icon(xml, main_wnd->window, style,
245 "button6", (gchar **) xpm_tree_view);
250 widget = glade_xml_get_widget(xml, "button4");
251 g_signal_emit_by_name(widget, "clicked");
254 widget = glade_xml_get_widget(xml, "button5");
255 g_signal_emit_by_name(widget, "clicked");
258 widget = glade_xml_get_widget(xml, "button6");
259 g_signal_emit_by_name(widget, "clicked");
263 txtbuf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w));
264 tag1 = gtk_text_buffer_create_tag(txtbuf, "mytag1",
266 "weight", PANGO_WEIGHT_BOLD,
268 tag2 = gtk_text_buffer_create_tag(txtbuf, "mytag2",
269 /*"style", PANGO_STYLE_OBLIQUE, */
272 sprintf(title, _("Linux Kernel v%s Configuration"),
273 getenv("KERNELVERSION"));
274 gtk_window_set_title(GTK_WINDOW(main_wnd), title);
276 gtk_widget_show(main_wnd);
279 void init_tree_model(void)
283 tree = tree2 = gtk_tree_store_new(COL_NUMBER,
284 G_TYPE_STRING, G_TYPE_STRING,
285 G_TYPE_STRING, G_TYPE_STRING,
286 G_TYPE_STRING, G_TYPE_STRING,
287 G_TYPE_POINTER, GDK_TYPE_COLOR,
288 G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF,
289 G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
290 G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
292 model2 = GTK_TREE_MODEL(tree2);
294 for (parents[0] = NULL, i = 1; i < 256; i++)
295 parents[i] = (GtkTreeIter *) g_malloc(sizeof(GtkTreeIter));
297 tree1 = gtk_tree_store_new(COL_NUMBER,
298 G_TYPE_STRING, G_TYPE_STRING,
299 G_TYPE_STRING, G_TYPE_STRING,
300 G_TYPE_STRING, G_TYPE_STRING,
301 G_TYPE_POINTER, GDK_TYPE_COLOR,
302 G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF,
303 G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
304 G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
306 model1 = GTK_TREE_MODEL(tree1);
309 void init_left_tree(void)
311 GtkTreeView *view = GTK_TREE_VIEW(tree1_w);
312 GtkCellRenderer *renderer;
313 GtkTreeSelection *sel;
314 GtkTreeViewColumn *column;
316 gtk_tree_view_set_model(view, model1);
317 gtk_tree_view_set_headers_visible(view, TRUE);
318 gtk_tree_view_set_rules_hint(view, FALSE);
320 column = gtk_tree_view_column_new();
321 gtk_tree_view_append_column(view, column);
322 gtk_tree_view_column_set_title(column, _("Options"));
324 renderer = gtk_cell_renderer_toggle_new();
325 gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
327 gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
329 "active", COL_BTNACT,
330 "inconsistent", COL_BTNINC,
331 "visible", COL_BTNVIS,
332 "radio", COL_BTNRAD, NULL);
333 renderer = gtk_cell_renderer_text_new();
334 gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
336 gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
342 sel = gtk_tree_view_get_selection(view);
343 gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
344 gtk_widget_realize(tree1_w);
347 static void renderer_edited(GtkCellRendererText * cell,
348 const gchar * path_string,
349 const gchar * new_text, gpointer user_data);
350 static void renderer_toggled(GtkCellRendererToggle * cellrenderertoggle,
351 gchar * arg1, gpointer user_data);
353 void init_right_tree(void)
355 GtkTreeView *view = GTK_TREE_VIEW(tree2_w);
356 GtkCellRenderer *renderer;
357 GtkTreeSelection *sel;
358 GtkTreeViewColumn *column;
361 gtk_tree_view_set_model(view, model2);
362 gtk_tree_view_set_headers_visible(view, TRUE);
363 gtk_tree_view_set_rules_hint(view, FALSE);
365 column = gtk_tree_view_column_new();
366 gtk_tree_view_append_column(view, column);
367 gtk_tree_view_column_set_title(column, _("Options"));
369 renderer = gtk_cell_renderer_pixbuf_new();
370 gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
372 gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
374 "pixbuf", COL_PIXBUF,
375 "visible", COL_PIXVIS, NULL);
376 renderer = gtk_cell_renderer_toggle_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 "active", COL_BTNACT,
382 "inconsistent", COL_BTNINC,
383 "visible", COL_BTNVIS,
384 "radio", COL_BTNRAD, NULL);
385 /*g_signal_connect(G_OBJECT(renderer), "toggled",
386 G_CALLBACK(renderer_toggled), NULL); */
387 renderer = gtk_cell_renderer_text_new();
388 gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
390 gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
396 renderer = gtk_cell_renderer_text_new();
397 gtk_tree_view_insert_column_with_attributes(view, -1,
402 renderer = gtk_cell_renderer_text_new();
403 gtk_tree_view_insert_column_with_attributes(view, -1,
408 renderer = gtk_cell_renderer_text_new();
409 gtk_tree_view_insert_column_with_attributes(view, -1,
414 renderer = gtk_cell_renderer_text_new();
415 gtk_tree_view_insert_column_with_attributes(view, -1,
420 renderer = gtk_cell_renderer_text_new();
421 gtk_tree_view_insert_column_with_attributes(view, -1,
422 _("Value"), renderer,
428 g_signal_connect(G_OBJECT(renderer), "edited",
429 G_CALLBACK(renderer_edited), NULL);
431 column = gtk_tree_view_get_column(view, COL_NAME);
432 gtk_tree_view_column_set_visible(column, show_name);
433 column = gtk_tree_view_get_column(view, COL_NO);
434 gtk_tree_view_column_set_visible(column, show_range);
435 column = gtk_tree_view_get_column(view, COL_MOD);
436 gtk_tree_view_column_set_visible(column, show_range);
437 column = gtk_tree_view_get_column(view, COL_YES);
438 gtk_tree_view_column_set_visible(column, show_range);
439 column = gtk_tree_view_get_column(view, COL_VALUE);
440 gtk_tree_view_column_set_visible(column, show_value);
443 for (i = 0; i < COL_VALUE; i++) {
444 column = gtk_tree_view_get_column(view, i);
445 gtk_tree_view_column_set_resizable(column, TRUE);
449 sel = gtk_tree_view_get_selection(view);
450 gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
454 /* Utility Functions */
457 static void text_insert_help(struct menu *menu)
459 GtkTextBuffer *buffer;
460 GtkTextIter start, end;
461 const char *prompt = menu_get_prompt(menu);
463 const char *help = _(nohelp_text);
467 else if (menu->sym->help)
468 help = _(menu->sym->help);
470 if (menu->sym && menu->sym->name)
471 name = g_strdup_printf(_(menu->sym->name));
475 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w));
476 gtk_text_buffer_get_bounds(buffer, &start, &end);
477 gtk_text_buffer_delete(buffer, &start, &end);
478 gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_w), 15);
480 gtk_text_buffer_get_end_iter(buffer, &end);
481 gtk_text_buffer_insert_with_tags(buffer, &end, prompt, -1, tag1,
483 gtk_text_buffer_insert_at_cursor(buffer, " ", 1);
484 gtk_text_buffer_get_end_iter(buffer, &end);
485 gtk_text_buffer_insert_with_tags(buffer, &end, name, -1, tag1,
487 gtk_text_buffer_insert_at_cursor(buffer, "\n\n", 2);
488 gtk_text_buffer_get_end_iter(buffer, &end);
489 gtk_text_buffer_insert_with_tags(buffer, &end, help, -1, tag2,
494 static void text_insert_msg(const char *title, const char *message)
496 GtkTextBuffer *buffer;
497 GtkTextIter start, end;
498 const char *msg = message;
500 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w));
501 gtk_text_buffer_get_bounds(buffer, &start, &end);
502 gtk_text_buffer_delete(buffer, &start, &end);
503 gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_w), 15);
505 gtk_text_buffer_get_end_iter(buffer, &end);
506 gtk_text_buffer_insert_with_tags(buffer, &end, title, -1, tag1,
508 gtk_text_buffer_insert_at_cursor(buffer, "\n\n", 2);
509 gtk_text_buffer_get_end_iter(buffer, &end);
510 gtk_text_buffer_insert_with_tags(buffer, &end, msg, -1, tag2,
515 /* Main Windows Callbacks */
517 void on_save1_activate(GtkMenuItem * menuitem, gpointer user_data);
518 gboolean on_window1_delete_event(GtkWidget * widget, GdkEvent * event,
521 GtkWidget *dialog, *label;
524 if (config_changed == FALSE)
527 dialog = gtk_dialog_new_with_buttons(_("Warning !"),
528 GTK_WINDOW(main_wnd),
531 GTK_DIALOG_DESTROY_WITH_PARENT),
537 GTK_RESPONSE_CANCEL, NULL);
538 gtk_dialog_set_default_response(GTK_DIALOG(dialog),
539 GTK_RESPONSE_CANCEL);
541 label = gtk_label_new(_("\nSave configuration ?\n"));
542 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), label);
543 gtk_widget_show(label);
545 result = gtk_dialog_run(GTK_DIALOG(dialog));
547 case GTK_RESPONSE_YES:
548 on_save1_activate(NULL, NULL);
550 case GTK_RESPONSE_NO:
552 case GTK_RESPONSE_CANCEL:
553 case GTK_RESPONSE_DELETE_EVENT:
555 gtk_widget_destroy(dialog);
563 void on_window1_destroy(GtkObject * object, gpointer user_data)
570 on_window1_size_request(GtkWidget * widget,
571 GtkRequisition * requisition, gpointer user_data)
576 if (widget->window == NULL)
577 gtk_window_get_default_size(GTK_WINDOW(main_wnd), &w, &h);
579 gdk_window_get_size(widget->window, &w, &h);
585 gtk_paned_set_position(GTK_PANED(vpaned), 2 * h / 3);
589 /* Menu & Toolbar Callbacks */
593 load_filename(GtkFileSelection * file_selector, gpointer user_data)
597 fn = gtk_file_selection_get_filename(GTK_FILE_SELECTION
601 text_insert_msg(_("Error"), _("Unable to load configuration !"));
603 display_tree(&rootmenu);
606 void on_load1_activate(GtkMenuItem * menuitem, gpointer user_data)
610 fs = gtk_file_selection_new(_("Load file..."));
611 g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs)->ok_button),
613 G_CALLBACK(load_filename), (gpointer) fs);
614 g_signal_connect_swapped(GTK_OBJECT
615 (GTK_FILE_SELECTION(fs)->ok_button),
616 "clicked", G_CALLBACK(gtk_widget_destroy),
618 g_signal_connect_swapped(GTK_OBJECT
619 (GTK_FILE_SELECTION(fs)->cancel_button),
620 "clicked", G_CALLBACK(gtk_widget_destroy),
626 void on_save1_activate(GtkMenuItem * menuitem, gpointer user_data)
628 if (conf_write(NULL))
629 text_insert_msg(_("Error"), _("Unable to save configuration !"));
631 config_changed = FALSE;
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_save_clicked(GtkButton * button, gpointer user_data)
826 on_save1_activate(NULL, user_data);
830 void on_single_clicked(GtkButton * button, gpointer user_data)
832 view_mode = SINGLE_VIEW;
833 gtk_paned_set_position(GTK_PANED(hpaned), 0);
834 gtk_widget_hide(tree1_w);
840 void on_split_clicked(GtkButton * button, gpointer user_data)
843 view_mode = SPLIT_VIEW;
844 gtk_widget_show(tree1_w);
845 gtk_window_get_default_size(GTK_WINDOW(main_wnd), &w, &h);
846 gtk_paned_set_position(GTK_PANED(hpaned), w / 2);
848 gtk_tree_store_clear(tree2);
851 /* Disable back btn, like in full mode. */
852 gtk_widget_set_sensitive(back_btn, FALSE);
856 void on_full_clicked(GtkButton * button, gpointer user_data)
858 view_mode = FULL_VIEW;
859 gtk_paned_set_position(GTK_PANED(hpaned), 0);
860 gtk_widget_hide(tree1_w);
862 gtk_tree_store_clear(tree2);
863 display_tree(&rootmenu);
864 gtk_widget_set_sensitive(back_btn, FALSE);
868 void on_collapse_clicked(GtkButton * button, gpointer user_data)
870 gtk_tree_view_collapse_all(GTK_TREE_VIEW(tree2_w));
874 void on_expand_clicked(GtkButton * button, gpointer user_data)
876 gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w));
880 /* CTree Callbacks */
882 /* Change hex/int/string value in the cell */
883 static void renderer_edited(GtkCellRendererText * cell,
884 const gchar * path_string,
885 const gchar * new_text, gpointer user_data)
887 GtkTreePath *path = gtk_tree_path_new_from_string(path_string);
889 const char *old_def, *new_def;
893 if (!gtk_tree_model_get_iter(model2, &iter, path))
896 gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
899 gtk_tree_model_get(model2, &iter, COL_VALUE, &old_def, -1);
902 sym_set_string_value(sym, new_def);
904 config_changed = TRUE;
905 update_tree(&rootmenu, NULL);
907 gtk_tree_path_free(path);
910 /* Change the value of a symbol and update the tree */
911 static void change_sym_value(struct menu *menu, gint col)
913 struct symbol *sym = menu->sym;
914 tristate oldval, newval;
921 else if (col == COL_MOD)
923 else if (col == COL_YES)
928 switch (sym_get_type(sym)) {
931 oldval = sym_get_tristate_value(sym);
932 if (!sym_tristate_within_range(sym, newval))
934 sym_set_tristate_value(sym, newval);
935 config_changed = TRUE;
936 if (view_mode == FULL_VIEW)
937 update_tree(&rootmenu, NULL);
938 else if (view_mode == SPLIT_VIEW) {
939 update_tree(browsed, NULL);
942 else if (view_mode == SINGLE_VIEW)
943 display_tree_part(); //fixme: keep exp/coll
953 static void toggle_sym_value(struct menu *menu)
958 sym_toggle_tristate_value(menu->sym);
959 if (view_mode == FULL_VIEW)
960 update_tree(&rootmenu, NULL);
961 else if (view_mode == SPLIT_VIEW) {
962 update_tree(browsed, NULL);
965 else if (view_mode == SINGLE_VIEW)
966 display_tree_part(); //fixme: keep exp/coll
969 static void renderer_toggled(GtkCellRendererToggle * cell,
970 gchar * path_string, gpointer user_data)
972 GtkTreePath *path, *sel_path = NULL;
973 GtkTreeIter iter, sel_iter;
974 GtkTreeSelection *sel;
977 path = gtk_tree_path_new_from_string(path_string);
978 if (!gtk_tree_model_get_iter(model2, &iter, path))
981 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree2_w));
982 if (gtk_tree_selection_get_selected(sel, NULL, &sel_iter))
983 sel_path = gtk_tree_model_get_path(model2, &sel_iter);
986 if (gtk_tree_path_compare(path, sel_path))
989 gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
990 toggle_sym_value(menu);
993 gtk_tree_path_free(sel_path);
995 gtk_tree_path_free(path);
998 static gint column2index(GtkTreeViewColumn * column)
1002 for (i = 0; i < COL_NUMBER; i++) {
1003 GtkTreeViewColumn *col;
1005 col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), i);
1014 /* User click: update choice (full) or goes down (single) */
1016 on_treeview2_button_press_event(GtkWidget * widget,
1017 GdkEventButton * event, gpointer user_data)
1019 GtkTreeView *view = GTK_TREE_VIEW(widget);
1021 GtkTreeViewColumn *column;
1026 #if GTK_CHECK_VERSION(2,1,4) // bug in ctree with earlier version of GTK
1027 gint tx = (gint) event->x;
1028 gint ty = (gint) event->y;
1031 gtk_tree_view_get_path_at_pos(view, tx, ty, &path, &column, &cx,
1034 gtk_tree_view_get_cursor(view, &path, &column);
1039 if (!gtk_tree_model_get_iter(model2, &iter, path))
1041 gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
1043 col = column2index(column);
1044 if (event->type == GDK_2BUTTON_PRESS) {
1045 enum prop_type ptype;
1046 ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
1048 if (ptype == P_MENU && view_mode != FULL_VIEW && col == COL_OPTION) {
1049 // goes down into menu
1051 display_tree_part();
1052 gtk_widget_set_sensitive(back_btn, TRUE);
1053 } else if ((col == COL_OPTION)) {
1054 toggle_sym_value(menu);
1055 gtk_tree_view_expand_row(view, path, TRUE);
1058 if (col == COL_VALUE) {
1059 toggle_sym_value(menu);
1060 gtk_tree_view_expand_row(view, path, TRUE);
1061 } else if (col == COL_NO || col == COL_MOD
1062 || col == COL_YES) {
1063 change_sym_value(menu, col);
1064 gtk_tree_view_expand_row(view, path, TRUE);
1071 /* Key pressed: update choice */
1073 on_treeview2_key_press_event(GtkWidget * widget,
1074 GdkEventKey * event, gpointer user_data)
1076 GtkTreeView *view = GTK_TREE_VIEW(widget);
1078 GtkTreeViewColumn *column;
1083 gtk_tree_view_get_cursor(view, &path, &column);
1087 if (event->keyval == GDK_space) {
1088 if (gtk_tree_view_row_expanded(view, path))
1089 gtk_tree_view_collapse_row(view, path);
1091 gtk_tree_view_expand_row(view, path, FALSE);
1094 if (event->keyval == GDK_KP_Enter) {
1096 if (widget == tree1_w)
1099 gtk_tree_model_get_iter(model2, &iter, path);
1100 gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
1102 if (!strcasecmp(event->string, "n"))
1104 else if (!strcasecmp(event->string, "m"))
1106 else if (!strcasecmp(event->string, "y"))
1110 change_sym_value(menu, col);
1116 /* Row selection changed: update help */
1118 on_treeview2_cursor_changed(GtkTreeView * treeview, gpointer user_data)
1120 GtkTreeSelection *selection;
1124 selection = gtk_tree_view_get_selection(treeview);
1125 if (gtk_tree_selection_get_selected(selection, &model2, &iter)) {
1126 gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
1127 text_insert_help(menu);
1132 /* User click: display sub-tree in the right frame. */
1134 on_treeview1_button_press_event(GtkWidget * widget,
1135 GdkEventButton * event, gpointer user_data)
1137 GtkTreeView *view = GTK_TREE_VIEW(widget);
1139 GtkTreeViewColumn *column;
1143 gint tx = (gint) event->x;
1144 gint ty = (gint) event->y;
1147 gtk_tree_view_get_path_at_pos(view, tx, ty, &path, &column, &cx,
1152 gtk_tree_model_get_iter(model1, &iter, path);
1153 gtk_tree_model_get(model1, &iter, COL_MENU, &menu, -1);
1155 if (event->type == GDK_2BUTTON_PRESS) {
1156 toggle_sym_value(menu);
1158 display_tree_part();
1161 display_tree_part();
1164 gtk_widget_realize(tree2_w);
1165 gtk_tree_view_set_cursor(view, path, NULL, FALSE);
1166 gtk_widget_grab_focus(tree2_w);
1172 /* Fill a row of strings */
1173 static gchar **fill_row(struct menu *menu)
1175 static gchar *row[COL_NUMBER];
1176 struct symbol *sym = menu->sym;
1180 enum prop_type ptype;
1183 for (i = COL_OPTION; i <= COL_COLOR; i++)
1185 bzero(row, sizeof(row));
1188 g_strdup_printf("%s %s", menu_get_prompt(menu),
1190 flags & SYMBOL_NEW ? "(NEW)" : "") :
1193 if (show_all && !menu_is_visible(menu))
1194 row[COL_COLOR] = g_strdup("DarkGray");
1196 row[COL_COLOR] = g_strdup("Black");
1198 ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
1201 row[COL_PIXBUF] = (gchar *) xpm_menu;
1202 if (view_mode == SINGLE_VIEW)
1203 row[COL_PIXVIS] = GINT_TO_POINTER(TRUE);
1204 row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
1207 row[COL_PIXBUF] = (gchar *) xpm_void;
1208 row[COL_PIXVIS] = GINT_TO_POINTER(FALSE);
1209 row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
1212 row[COL_PIXBUF] = (gchar *) xpm_void;
1213 row[COL_PIXVIS] = GINT_TO_POINTER(FALSE);
1214 row[COL_BTNVIS] = GINT_TO_POINTER(TRUE);
1220 row[COL_NAME] = g_strdup(sym->name);
1222 sym_calc_value(sym);
1223 sym->flags &= ~SYMBOL_CHANGED;
1225 if (sym_is_choice(sym)) { // parse childs for getting final value
1227 struct symbol *def_sym = sym_get_choice_value(sym);
1228 struct menu *def_menu = NULL;
1230 row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
1232 for (child = menu->list; child; child = child->next) {
1233 if (menu_is_visible(child)
1234 && child->sym == def_sym)
1240 g_strdup(menu_get_prompt(def_menu));
1242 if (sym->flags & SYMBOL_CHOICEVAL)
1243 row[COL_BTNRAD] = GINT_TO_POINTER(TRUE);
1245 stype = sym_get_type(sym);
1248 if (GPOINTER_TO_INT(row[COL_PIXVIS]) == FALSE)
1249 row[COL_BTNVIS] = GINT_TO_POINTER(TRUE);
1250 if (sym_is_choice(sym))
1253 val = sym_get_tristate_value(sym);
1256 row[COL_NO] = g_strdup("N");
1257 row[COL_VALUE] = g_strdup("N");
1258 row[COL_BTNACT] = GINT_TO_POINTER(FALSE);
1259 row[COL_BTNINC] = GINT_TO_POINTER(FALSE);
1262 row[COL_MOD] = g_strdup("M");
1263 row[COL_VALUE] = g_strdup("M");
1264 row[COL_BTNINC] = GINT_TO_POINTER(TRUE);
1267 row[COL_YES] = g_strdup("Y");
1268 row[COL_VALUE] = g_strdup("Y");
1269 row[COL_BTNACT] = GINT_TO_POINTER(TRUE);
1270 row[COL_BTNINC] = GINT_TO_POINTER(FALSE);
1274 if (val != no && sym_tristate_within_range(sym, no))
1275 row[COL_NO] = g_strdup("_");
1276 if (val != mod && sym_tristate_within_range(sym, mod))
1277 row[COL_MOD] = g_strdup("_");
1278 if (val != yes && sym_tristate_within_range(sym, yes))
1279 row[COL_YES] = g_strdup("_");
1284 def = sym_get_string_value(sym);
1285 row[COL_VALUE] = g_strdup(def);
1286 row[COL_EDIT] = GINT_TO_POINTER(TRUE);
1287 row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
1295 /* Set the node content with a row of strings */
1296 static void set_node(GtkTreeIter * node, struct menu *menu, gchar ** row)
1302 pix = gdk_pixbuf_new_from_xpm_data((const char **)
1305 gdk_color_parse(row[COL_COLOR], &color);
1306 gdk_colormap_alloc_colors(gdk_colormap_get_system(), &color, 1,
1307 FALSE, FALSE, &success);
1309 gtk_tree_store_set(tree, node,
1310 COL_OPTION, row[COL_OPTION],
1311 COL_NAME, row[COL_NAME],
1312 COL_NO, row[COL_NO],
1313 COL_MOD, row[COL_MOD],
1314 COL_YES, row[COL_YES],
1315 COL_VALUE, row[COL_VALUE],
1316 COL_MENU, (gpointer) menu,
1318 COL_EDIT, GPOINTER_TO_INT(row[COL_EDIT]),
1320 COL_PIXVIS, GPOINTER_TO_INT(row[COL_PIXVIS]),
1321 COL_BTNVIS, GPOINTER_TO_INT(row[COL_BTNVIS]),
1322 COL_BTNACT, GPOINTER_TO_INT(row[COL_BTNACT]),
1323 COL_BTNINC, GPOINTER_TO_INT(row[COL_BTNINC]),
1324 COL_BTNRAD, GPOINTER_TO_INT(row[COL_BTNRAD]),
1327 g_object_unref(pix);
1331 /* Add a node to the tree */
1332 static void place_node(struct menu *menu, char **row)
1334 GtkTreeIter *parent = parents[indent - 1];
1335 GtkTreeIter *node = parents[indent];
1337 gtk_tree_store_append(tree, node, parent);
1338 set_node(node, menu, row);
1342 /* Find a node in the GTK+ tree */
1343 static GtkTreeIter found;
1346 * Find a menu in the GtkTree starting at parent.
1348 GtkTreeIter *gtktree_iter_find_node(GtkTreeIter * parent,
1349 struct menu *tofind)
1352 GtkTreeIter *child = &iter;
1356 valid = gtk_tree_model_iter_children(model2, child, parent);
1360 gtk_tree_model_get(model2, child, 6, &menu, -1);
1362 if (menu == tofind) {
1363 memcpy(&found, child, sizeof(GtkTreeIter));
1367 ret = gtktree_iter_find_node(child, tofind);
1371 valid = gtk_tree_model_iter_next(model2, child);
1379 * Update the tree by adding/removing entries
1380 * Does not change other nodes
1382 static void update_tree(struct menu *src, GtkTreeIter * dst)
1384 struct menu *child1;
1385 GtkTreeIter iter, tmp;
1386 GtkTreeIter *child2 = &iter;
1388 GtkTreeIter *sibling;
1390 struct property *prop;
1391 struct menu *menu1, *menu2;
1393 if (src == &rootmenu)
1396 valid = gtk_tree_model_iter_children(model2, child2, dst);
1397 for (child1 = src->list; child1; child1 = child1->next) {
1399 prop = child1->prompt;
1405 gtk_tree_model_get(model2, child2, COL_MENU,
1408 menu2 = NULL; // force adding of a first child
1411 printf("%*c%s | %s\n", indent, ' ',
1412 menu1 ? menu_get_prompt(menu1) : "nil",
1413 menu2 ? menu_get_prompt(menu2) : "nil");
1416 if (!menu_is_visible(child1) && !show_all) { // remove node
1417 if (gtktree_iter_find_node(dst, menu1) != NULL) {
1418 memcpy(&tmp, child2, sizeof(GtkTreeIter));
1419 valid = gtk_tree_model_iter_next(model2,
1421 gtk_tree_store_remove(tree2, &tmp);
1423 return; // next parent
1425 goto reparse; // next child
1430 if (menu1 != menu2) {
1431 if (gtktree_iter_find_node(dst, menu1) == NULL) { // add node
1432 if (!valid && !menu2)
1436 gtk_tree_store_insert_before(tree2,
1439 set_node(child2, menu1, fill_row(menu1));
1442 } else { // remove node
1443 memcpy(&tmp, child2, sizeof(GtkTreeIter));
1444 valid = gtk_tree_model_iter_next(model2,
1446 gtk_tree_store_remove(tree2, &tmp);
1448 return; // next parent
1450 goto reparse; // next child
1452 } else if (sym && (sym->flags & SYMBOL_CHANGED)) {
1453 set_node(child2, menu1, fill_row(menu1));
1457 update_tree(child1, child2);
1460 valid = gtk_tree_model_iter_next(model2, child2);
1465 /* Display the whole tree (single/split/full view) */
1466 static void display_tree(struct menu *menu)
1469 struct property *prop;
1471 enum prop_type ptype;
1473 if (menu == &rootmenu) {
1475 current = &rootmenu;
1478 for (child = menu->list; child; child = child->next) {
1479 prop = child->prompt;
1481 ptype = prop ? prop->type : P_UNKNOWN;
1484 sym->flags &= ~SYMBOL_CHANGED;
1486 if ((view_mode == SPLIT_VIEW)
1487 && !(child->flags & MENU_ROOT) && (tree == tree1))
1490 if ((view_mode == SPLIT_VIEW) && (child->flags & MENU_ROOT)
1494 if (menu_is_visible(child) || show_all)
1495 place_node(child, fill_row(child));
1497 printf("%*c%s: ", indent, ' ', menu_get_prompt(child));
1498 printf("%s", child->flags & MENU_ROOT ? "rootmenu | " : "");
1499 dbg_print_ptype(ptype);
1502 dbg_print_stype(sym->type);
1504 dbg_print_flags(sym->flags);
1509 if ((view_mode != FULL_VIEW) && (ptype == P_MENU)
1513 if (((menu != &rootmenu) && !(menu->flags & MENU_ROOT))
1514 || (view_mode == FULL_VIEW)
1515 || (view_mode == SPLIT_VIEW))*/
1516 if (((view_mode == SINGLE_VIEW) && (menu->flags & MENU_ROOT))
1517 || (view_mode == FULL_VIEW)
1518 || (view_mode == SPLIT_VIEW)) {
1520 display_tree(child);
1526 /* Display a part of the tree starting at current node (single/split view) */
1527 static void display_tree_part(void)
1530 gtk_tree_store_clear(tree2);
1531 if (view_mode == SINGLE_VIEW)
1532 display_tree(current);
1533 else if (view_mode == SPLIT_VIEW)
1534 display_tree(browsed);
1535 gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w));
1538 /* Display the list in the left frame (split view) */
1539 static void display_list(void)
1542 gtk_tree_store_clear(tree1);
1545 display_tree(&rootmenu);
1546 gtk_tree_view_expand_all(GTK_TREE_VIEW(tree1_w));
1550 void fixup_rootmenu(struct menu *menu)
1553 static int menu_cnt = 0;
1555 menu->flags |= MENU_ROOT;
1556 for (child = menu->list; child; child = child->next) {
1557 if (child->prompt && child->prompt->type == P_MENU) {
1559 fixup_rootmenu(child);
1561 } else if (!menu_cnt)
1562 fixup_rootmenu(child);
1568 int main(int ac, char *av[])
1574 #ifndef LKC_DIRECT_LINK
1578 bindtextdomain(PACKAGE, LOCALEDIR);
1579 bind_textdomain_codeset(PACKAGE, "UTF-8");
1580 textdomain(PACKAGE);
1587 //add_pixmap_directory (PACKAGE_DATA_DIR "/" PACKAGE "/pixmaps");
1588 //add_pixmap_directory (PACKAGE_SOURCE_DIR "/pixmaps");
1590 /* Determine GUI path */
1591 env = getenv(SRCTREE);
1593 glade_file = g_strconcat(env, "/scripts/kconfig/gconf.glade", NULL);
1594 else if (av[0][0] == '/')
1595 glade_file = g_strconcat(av[0], ".glade", NULL);
1597 glade_file = g_strconcat(g_get_current_dir(), "/", av[0], ".glade", NULL);
1599 /* Load the interface and connect signals */
1600 init_main_window(glade_file);
1606 if (ac > 1 && av[1][0] == '-') {
1613 printf("%s <config>\n", av[0]);
1621 fixup_rootmenu(&rootmenu);
1624 switch (view_mode) {
1626 display_tree_part();
1632 display_tree(&rootmenu);