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_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 style = gtk_widget_get_style(main_wnd);
228 widget = glade_xml_get_widget(xml, "toolbar1");
230 #if 0 /* Use stock Gtk icons instead */
231 replace_button_icon(xml, main_wnd->window, style,
232 "button1", (gchar **) xpm_back);
233 replace_button_icon(xml, main_wnd->window, style,
234 "button2", (gchar **) xpm_load);
235 replace_button_icon(xml, main_wnd->window, style,
236 "button3", (gchar **) xpm_save);
238 replace_button_icon(xml, main_wnd->window, style,
239 "button4", (gchar **) xpm_single_view);
240 replace_button_icon(xml, main_wnd->window, style,
241 "button5", (gchar **) xpm_split_view);
242 replace_button_icon(xml, main_wnd->window, style,
243 "button6", (gchar **) xpm_tree_view);
248 widget = glade_xml_get_widget(xml, "button4");
249 g_signal_emit_by_name(widget, "clicked");
252 widget = glade_xml_get_widget(xml, "button5");
253 g_signal_emit_by_name(widget, "clicked");
256 widget = glade_xml_get_widget(xml, "button6");
257 g_signal_emit_by_name(widget, "clicked");
261 txtbuf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w));
262 tag1 = gtk_text_buffer_create_tag(txtbuf, "mytag1",
264 "weight", PANGO_WEIGHT_BOLD,
266 tag2 = gtk_text_buffer_create_tag(txtbuf, "mytag2",
267 /*"style", PANGO_STYLE_OBLIQUE, */
270 sprintf(title, _("Linux Kernel v%s Configuration"),
271 getenv("KERNELVERSION"));
272 gtk_window_set_title(GTK_WINDOW(main_wnd), title);
274 gtk_widget_show(main_wnd);
277 void init_tree_model(void)
281 tree = tree2 = gtk_tree_store_new(COL_NUMBER,
282 G_TYPE_STRING, G_TYPE_STRING,
283 G_TYPE_STRING, G_TYPE_STRING,
284 G_TYPE_STRING, G_TYPE_STRING,
285 G_TYPE_POINTER, GDK_TYPE_COLOR,
286 G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF,
287 G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
288 G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
290 model2 = GTK_TREE_MODEL(tree2);
292 for (parents[0] = NULL, i = 1; i < 256; i++)
293 parents[i] = (GtkTreeIter *) g_malloc(sizeof(GtkTreeIter));
295 tree1 = gtk_tree_store_new(COL_NUMBER,
296 G_TYPE_STRING, G_TYPE_STRING,
297 G_TYPE_STRING, G_TYPE_STRING,
298 G_TYPE_STRING, G_TYPE_STRING,
299 G_TYPE_POINTER, GDK_TYPE_COLOR,
300 G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF,
301 G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
302 G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
304 model1 = GTK_TREE_MODEL(tree1);
307 void init_left_tree(void)
309 GtkTreeView *view = GTK_TREE_VIEW(tree1_w);
310 GtkCellRenderer *renderer;
311 GtkTreeSelection *sel;
312 GtkTreeViewColumn *column;
314 gtk_tree_view_set_model(view, model1);
315 gtk_tree_view_set_headers_visible(view, TRUE);
316 gtk_tree_view_set_rules_hint(view, FALSE);
318 column = gtk_tree_view_column_new();
319 gtk_tree_view_append_column(view, column);
320 gtk_tree_view_column_set_title(column, _("Options"));
322 renderer = gtk_cell_renderer_toggle_new();
323 gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
325 gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
327 "active", COL_BTNACT,
328 "inconsistent", COL_BTNINC,
329 "visible", COL_BTNVIS,
330 "radio", COL_BTNRAD, NULL);
331 renderer = gtk_cell_renderer_text_new();
332 gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
334 gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
340 sel = gtk_tree_view_get_selection(view);
341 gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
342 gtk_widget_realize(tree1_w);
345 static void renderer_edited(GtkCellRendererText * cell,
346 const gchar * path_string,
347 const gchar * new_text, gpointer user_data);
348 static void renderer_toggled(GtkCellRendererToggle * cellrenderertoggle,
349 gchar * arg1, gpointer user_data);
351 void init_right_tree(void)
353 GtkTreeView *view = GTK_TREE_VIEW(tree2_w);
354 GtkCellRenderer *renderer;
355 GtkTreeSelection *sel;
356 GtkTreeViewColumn *column;
359 gtk_tree_view_set_model(view, model2);
360 gtk_tree_view_set_headers_visible(view, TRUE);
361 gtk_tree_view_set_rules_hint(view, FALSE);
363 column = gtk_tree_view_column_new();
364 gtk_tree_view_append_column(view, column);
365 gtk_tree_view_column_set_title(column, _("Options"));
367 renderer = gtk_cell_renderer_pixbuf_new();
368 gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
370 gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
372 "pixbuf", COL_PIXBUF,
373 "visible", COL_PIXVIS, NULL);
374 renderer = gtk_cell_renderer_toggle_new();
375 gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
377 gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
379 "active", COL_BTNACT,
380 "inconsistent", COL_BTNINC,
381 "visible", COL_BTNVIS,
382 "radio", COL_BTNRAD, NULL);
383 /*g_signal_connect(G_OBJECT(renderer), "toggled",
384 G_CALLBACK(renderer_toggled), NULL); */
385 renderer = gtk_cell_renderer_text_new();
386 gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
388 gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
394 renderer = gtk_cell_renderer_text_new();
395 gtk_tree_view_insert_column_with_attributes(view, -1,
400 renderer = gtk_cell_renderer_text_new();
401 gtk_tree_view_insert_column_with_attributes(view, -1,
406 renderer = gtk_cell_renderer_text_new();
407 gtk_tree_view_insert_column_with_attributes(view, -1,
412 renderer = gtk_cell_renderer_text_new();
413 gtk_tree_view_insert_column_with_attributes(view, -1,
418 renderer = gtk_cell_renderer_text_new();
419 gtk_tree_view_insert_column_with_attributes(view, -1,
420 _("Value"), renderer,
426 g_signal_connect(G_OBJECT(renderer), "edited",
427 G_CALLBACK(renderer_edited), NULL);
429 column = gtk_tree_view_get_column(view, COL_NAME);
430 gtk_tree_view_column_set_visible(column, show_name);
431 column = gtk_tree_view_get_column(view, COL_NO);
432 gtk_tree_view_column_set_visible(column, show_range);
433 column = gtk_tree_view_get_column(view, COL_MOD);
434 gtk_tree_view_column_set_visible(column, show_range);
435 column = gtk_tree_view_get_column(view, COL_YES);
436 gtk_tree_view_column_set_visible(column, show_range);
437 column = gtk_tree_view_get_column(view, COL_VALUE);
438 gtk_tree_view_column_set_visible(column, show_value);
441 for (i = 0; i < COL_VALUE; i++) {
442 column = gtk_tree_view_get_column(view, i);
443 gtk_tree_view_column_set_resizable(column, TRUE);
447 sel = gtk_tree_view_get_selection(view);
448 gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
452 /* Utility Functions */
455 static void text_insert_help(struct menu *menu)
457 GtkTextBuffer *buffer;
458 GtkTextIter start, end;
459 const char *prompt = menu_get_prompt(menu);
461 const char *help = _(nohelp_text);
465 else if (menu->sym->help)
466 help = _(menu->sym->help);
468 if (menu->sym && menu->sym->name)
469 name = g_strdup_printf(_(menu->sym->name));
473 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w));
474 gtk_text_buffer_get_bounds(buffer, &start, &end);
475 gtk_text_buffer_delete(buffer, &start, &end);
476 gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_w), 15);
478 gtk_text_buffer_get_end_iter(buffer, &end);
479 gtk_text_buffer_insert_with_tags(buffer, &end, prompt, -1, tag1,
481 gtk_text_buffer_insert_at_cursor(buffer, " ", 1);
482 gtk_text_buffer_get_end_iter(buffer, &end);
483 gtk_text_buffer_insert_with_tags(buffer, &end, name, -1, tag1,
485 gtk_text_buffer_insert_at_cursor(buffer, "\n\n", 2);
486 gtk_text_buffer_get_end_iter(buffer, &end);
487 gtk_text_buffer_insert_with_tags(buffer, &end, help, -1, tag2,
492 static void text_insert_msg(const char *title, const char *message)
494 GtkTextBuffer *buffer;
495 GtkTextIter start, end;
496 const char *msg = message;
498 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w));
499 gtk_text_buffer_get_bounds(buffer, &start, &end);
500 gtk_text_buffer_delete(buffer, &start, &end);
501 gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_w), 15);
503 gtk_text_buffer_get_end_iter(buffer, &end);
504 gtk_text_buffer_insert_with_tags(buffer, &end, title, -1, tag1,
506 gtk_text_buffer_insert_at_cursor(buffer, "\n\n", 2);
507 gtk_text_buffer_get_end_iter(buffer, &end);
508 gtk_text_buffer_insert_with_tags(buffer, &end, msg, -1, tag2,
513 /* Main Windows Callbacks */
515 void on_save1_activate(GtkMenuItem * menuitem, gpointer user_data);
516 gboolean on_window1_delete_event(GtkWidget * widget, GdkEvent * event,
519 GtkWidget *dialog, *label;
522 if (config_changed == FALSE)
525 dialog = gtk_dialog_new_with_buttons(_("Warning !"),
526 GTK_WINDOW(main_wnd),
529 GTK_DIALOG_DESTROY_WITH_PARENT),
535 GTK_RESPONSE_CANCEL, NULL);
536 gtk_dialog_set_default_response(GTK_DIALOG(dialog),
537 GTK_RESPONSE_CANCEL);
539 label = gtk_label_new(_("\nSave configuration ?\n"));
540 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), label);
541 gtk_widget_show(label);
543 result = gtk_dialog_run(GTK_DIALOG(dialog));
545 case GTK_RESPONSE_YES:
546 on_save1_activate(NULL, NULL);
548 case GTK_RESPONSE_NO:
550 case GTK_RESPONSE_CANCEL:
551 case GTK_RESPONSE_DELETE_EVENT:
553 gtk_widget_destroy(dialog);
561 void on_window1_destroy(GtkObject * object, gpointer user_data)
568 on_window1_size_request(GtkWidget * widget,
569 GtkRequisition * requisition, gpointer user_data)
574 if (widget->window == NULL)
575 gtk_window_get_default_size(GTK_WINDOW(main_wnd), &w, &h);
577 gdk_window_get_size(widget->window, &w, &h);
583 gtk_paned_set_position(GTK_PANED(vpaned), 2 * h / 3);
587 /* Menu & Toolbar Callbacks */
591 load_filename(GtkFileSelection * file_selector, gpointer user_data)
595 fn = gtk_file_selection_get_filename(GTK_FILE_SELECTION
599 text_insert_msg(_("Error"), _("Unable to load configuration !"));
601 display_tree(&rootmenu);
604 void on_load1_activate(GtkMenuItem * menuitem, gpointer user_data)
608 fs = gtk_file_selection_new(_("Load file..."));
609 g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs)->ok_button),
611 G_CALLBACK(load_filename), (gpointer) fs);
612 g_signal_connect_swapped(GTK_OBJECT
613 (GTK_FILE_SELECTION(fs)->ok_button),
614 "clicked", G_CALLBACK(gtk_widget_destroy),
616 g_signal_connect_swapped(GTK_OBJECT
617 (GTK_FILE_SELECTION(fs)->cancel_button),
618 "clicked", G_CALLBACK(gtk_widget_destroy),
624 void on_save1_activate(GtkMenuItem * menuitem, gpointer user_data)
626 if (conf_write(NULL))
627 text_insert_msg(_("Error"), _("Unable to save configuration !"));
629 config_changed = FALSE;
634 store_filename(GtkFileSelection * file_selector, gpointer user_data)
638 fn = gtk_file_selection_get_filename(GTK_FILE_SELECTION
642 text_insert_msg(_("Error"), _("Unable to save configuration !"));
644 gtk_widget_destroy(GTK_WIDGET(user_data));
647 void on_save_as1_activate(GtkMenuItem * menuitem, gpointer user_data)
651 fs = gtk_file_selection_new(_("Save file as..."));
652 g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs)->ok_button),
654 G_CALLBACK(store_filename), (gpointer) fs);
655 g_signal_connect_swapped(GTK_OBJECT
656 (GTK_FILE_SELECTION(fs)->ok_button),
657 "clicked", G_CALLBACK(gtk_widget_destroy),
659 g_signal_connect_swapped(GTK_OBJECT
660 (GTK_FILE_SELECTION(fs)->cancel_button),
661 "clicked", G_CALLBACK(gtk_widget_destroy),
667 void on_quit1_activate(GtkMenuItem * menuitem, gpointer user_data)
669 if (!on_window1_delete_event(NULL, NULL, NULL))
670 gtk_widget_destroy(GTK_WIDGET(main_wnd));
674 void on_show_name1_activate(GtkMenuItem * menuitem, gpointer user_data)
676 GtkTreeViewColumn *col;
678 show_name = GTK_CHECK_MENU_ITEM(menuitem)->active;
679 col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_NAME);
681 gtk_tree_view_column_set_visible(col, show_name);
685 void on_show_range1_activate(GtkMenuItem * menuitem, gpointer user_data)
687 GtkTreeViewColumn *col;
689 show_range = GTK_CHECK_MENU_ITEM(menuitem)->active;
690 col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_NO);
692 gtk_tree_view_column_set_visible(col, show_range);
693 col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_MOD);
695 gtk_tree_view_column_set_visible(col, show_range);
696 col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_YES);
698 gtk_tree_view_column_set_visible(col, show_range);
703 void on_show_data1_activate(GtkMenuItem * menuitem, gpointer user_data)
705 GtkTreeViewColumn *col;
707 show_value = GTK_CHECK_MENU_ITEM(menuitem)->active;
708 col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_VALUE);
710 gtk_tree_view_column_set_visible(col, show_value);
715 on_show_all_options1_activate(GtkMenuItem * menuitem, gpointer user_data)
717 show_all = GTK_CHECK_MENU_ITEM(menuitem)->active;
719 gtk_tree_store_clear(tree2);
720 display_tree(&rootmenu); // instead of update_tree to speed-up
725 on_show_debug_info1_activate(GtkMenuItem * menuitem, gpointer user_data)
727 show_debug = GTK_CHECK_MENU_ITEM(menuitem)->active;
728 update_tree(&rootmenu, NULL);
732 void on_introduction1_activate(GtkMenuItem * menuitem, gpointer user_data)
735 const gchar *intro_text = _(
736 "Welcome to gkc, the GTK+ graphical kernel configuration tool\n"
738 "For each option, a blank box indicates the feature is disabled, a\n"
739 "check indicates it is enabled, and a dot indicates that it is to\n"
740 "be compiled as a module. Clicking on the box will cycle through the three states.\n"
742 "If you do not see an option (e.g., a device driver) that you\n"
743 "believe should be present, try turning on Show All Options\n"
744 "under the Options menu.\n"
745 "Although there is no cross reference yet to help you figure out\n"
746 "what other options must be enabled to support the option you\n"
747 "are interested in, you can still view the help of a grayed-out\n"
750 "Toggling Show Debug Info under the Options menu will show \n"
751 "the dependencies, which you can then match by examining other options.");
753 dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
754 GTK_DIALOG_DESTROY_WITH_PARENT,
756 GTK_BUTTONS_CLOSE, intro_text);
757 g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
758 G_CALLBACK(gtk_widget_destroy),
760 gtk_widget_show_all(dialog);
764 void on_about1_activate(GtkMenuItem * menuitem, gpointer user_data)
767 const gchar *about_text =
768 _("gkc is copyright (c) 2002 Romain Lievin <roms@lpg.ticalc.org>.\n"
769 "Based on the source code from Roman Zippel.\n");
771 dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
772 GTK_DIALOG_DESTROY_WITH_PARENT,
774 GTK_BUTTONS_CLOSE, about_text);
775 g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
776 G_CALLBACK(gtk_widget_destroy),
778 gtk_widget_show_all(dialog);
782 void on_license1_activate(GtkMenuItem * menuitem, gpointer user_data)
785 const gchar *license_text =
786 _("gkc is released under the terms of the GNU GPL v2.\n"
787 "For more information, please see the source code or\n"
788 "visit http://www.fsf.org/licenses/licenses.html\n");
790 dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
791 GTK_DIALOG_DESTROY_WITH_PARENT,
793 GTK_BUTTONS_CLOSE, license_text);
794 g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
795 G_CALLBACK(gtk_widget_destroy),
797 gtk_widget_show_all(dialog);
801 void on_back_clicked(GtkButton * button, gpointer user_data)
803 enum prop_type ptype;
805 current = current->parent;
806 ptype = current->prompt ? current->prompt->type : P_UNKNOWN;
808 current = current->parent;
811 if (current == &rootmenu)
812 gtk_widget_set_sensitive(back_btn, FALSE);
816 void on_load_clicked(GtkButton * button, gpointer user_data)
818 on_load1_activate(NULL, user_data);
822 void on_save_clicked(GtkButton * button, gpointer user_data)
824 on_save1_activate(NULL, user_data);
828 void on_single_clicked(GtkButton * button, gpointer user_data)
830 view_mode = SINGLE_VIEW;
831 gtk_paned_set_position(GTK_PANED(hpaned), 0);
832 gtk_widget_hide(tree1_w);
838 void on_split_clicked(GtkButton * button, gpointer user_data)
841 view_mode = SPLIT_VIEW;
842 gtk_widget_show(tree1_w);
843 gtk_window_get_default_size(GTK_WINDOW(main_wnd), &w, &h);
844 gtk_paned_set_position(GTK_PANED(hpaned), w / 2);
846 gtk_tree_store_clear(tree2);
849 /* Disable back btn, like in full mode. */
850 gtk_widget_set_sensitive(back_btn, FALSE);
854 void on_full_clicked(GtkButton * button, gpointer user_data)
856 view_mode = FULL_VIEW;
857 gtk_paned_set_position(GTK_PANED(hpaned), 0);
858 gtk_widget_hide(tree1_w);
860 gtk_tree_store_clear(tree2);
861 display_tree(&rootmenu);
862 gtk_widget_set_sensitive(back_btn, FALSE);
866 void on_collapse_clicked(GtkButton * button, gpointer user_data)
868 gtk_tree_view_collapse_all(GTK_TREE_VIEW(tree2_w));
872 void on_expand_clicked(GtkButton * button, gpointer user_data)
874 gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w));
878 /* CTree Callbacks */
880 /* Change hex/int/string value in the cell */
881 static void renderer_edited(GtkCellRendererText * cell,
882 const gchar * path_string,
883 const gchar * new_text, gpointer user_data)
885 GtkTreePath *path = gtk_tree_path_new_from_string(path_string);
887 const char *old_def, *new_def;
891 if (!gtk_tree_model_get_iter(model2, &iter, path))
894 gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
897 gtk_tree_model_get(model2, &iter, COL_VALUE, &old_def, -1);
900 sym_set_string_value(sym, new_def);
902 config_changed = TRUE;
903 update_tree(&rootmenu, NULL);
905 gtk_tree_path_free(path);
908 /* Change the value of a symbol and update the tree */
909 static void change_sym_value(struct menu *menu, gint col)
911 struct symbol *sym = menu->sym;
912 tristate oldval, newval;
919 else if (col == COL_MOD)
921 else if (col == COL_YES)
926 switch (sym_get_type(sym)) {
929 oldval = sym_get_tristate_value(sym);
930 if (!sym_tristate_within_range(sym, newval))
932 sym_set_tristate_value(sym, newval);
933 config_changed = TRUE;
934 if (view_mode == FULL_VIEW)
935 update_tree(&rootmenu, NULL);
936 else if (view_mode == SPLIT_VIEW) {
937 update_tree(browsed, NULL);
940 else if (view_mode == SINGLE_VIEW)
941 display_tree_part(); //fixme: keep exp/coll
951 static void toggle_sym_value(struct menu *menu)
956 sym_toggle_tristate_value(menu->sym);
957 if (view_mode == FULL_VIEW)
958 update_tree(&rootmenu, NULL);
959 else if (view_mode == SPLIT_VIEW) {
960 update_tree(browsed, NULL);
963 else if (view_mode == SINGLE_VIEW)
964 display_tree_part(); //fixme: keep exp/coll
967 static void renderer_toggled(GtkCellRendererToggle * cell,
968 gchar * path_string, gpointer user_data)
970 GtkTreePath *path, *sel_path = NULL;
971 GtkTreeIter iter, sel_iter;
972 GtkTreeSelection *sel;
975 path = gtk_tree_path_new_from_string(path_string);
976 if (!gtk_tree_model_get_iter(model2, &iter, path))
979 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree2_w));
980 if (gtk_tree_selection_get_selected(sel, NULL, &sel_iter))
981 sel_path = gtk_tree_model_get_path(model2, &sel_iter);
984 if (gtk_tree_path_compare(path, sel_path))
987 gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
988 toggle_sym_value(menu);
991 gtk_tree_path_free(sel_path);
993 gtk_tree_path_free(path);
996 static gint column2index(GtkTreeViewColumn * column)
1000 for (i = 0; i < COL_NUMBER; i++) {
1001 GtkTreeViewColumn *col;
1003 col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), i);
1012 /* User click: update choice (full) or goes down (single) */
1014 on_treeview2_button_press_event(GtkWidget * widget,
1015 GdkEventButton * event, gpointer user_data)
1017 GtkTreeView *view = GTK_TREE_VIEW(widget);
1019 GtkTreeViewColumn *column;
1024 #if GTK_CHECK_VERSION(2,1,4) // bug in ctree with earlier version of GTK
1025 gint tx = (gint) event->x;
1026 gint ty = (gint) event->y;
1029 gtk_tree_view_get_path_at_pos(view, tx, ty, &path, &column, &cx,
1032 gtk_tree_view_get_cursor(view, &path, &column);
1037 if (!gtk_tree_model_get_iter(model2, &iter, path))
1039 gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
1041 col = column2index(column);
1042 if (event->type == GDK_2BUTTON_PRESS) {
1043 enum prop_type ptype;
1044 ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
1046 if (ptype == P_MENU && view_mode != FULL_VIEW && col == COL_OPTION) {
1047 // goes down into menu
1049 display_tree_part();
1050 gtk_widget_set_sensitive(back_btn, TRUE);
1051 } else if ((col == COL_OPTION)) {
1052 toggle_sym_value(menu);
1053 gtk_tree_view_expand_row(view, path, TRUE);
1056 if (col == COL_VALUE) {
1057 toggle_sym_value(menu);
1058 gtk_tree_view_expand_row(view, path, TRUE);
1059 } else if (col == COL_NO || col == COL_MOD
1060 || col == COL_YES) {
1061 change_sym_value(menu, col);
1062 gtk_tree_view_expand_row(view, path, TRUE);
1069 /* Key pressed: update choice */
1071 on_treeview2_key_press_event(GtkWidget * widget,
1072 GdkEventKey * event, gpointer user_data)
1074 GtkTreeView *view = GTK_TREE_VIEW(widget);
1076 GtkTreeViewColumn *column;
1081 gtk_tree_view_get_cursor(view, &path, &column);
1085 if (event->keyval == GDK_space) {
1086 if (gtk_tree_view_row_expanded(view, path))
1087 gtk_tree_view_collapse_row(view, path);
1089 gtk_tree_view_expand_row(view, path, FALSE);
1092 if (event->keyval == GDK_KP_Enter) {
1094 if (widget == tree1_w)
1097 gtk_tree_model_get_iter(model2, &iter, path);
1098 gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
1100 if (!strcasecmp(event->string, "n"))
1102 else if (!strcasecmp(event->string, "m"))
1104 else if (!strcasecmp(event->string, "y"))
1108 change_sym_value(menu, col);
1114 /* Row selection changed: update help */
1116 on_treeview2_cursor_changed(GtkTreeView * treeview, gpointer user_data)
1118 GtkTreeSelection *selection;
1122 selection = gtk_tree_view_get_selection(treeview);
1123 if (gtk_tree_selection_get_selected(selection, &model2, &iter)) {
1124 gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
1125 text_insert_help(menu);
1130 /* User click: display sub-tree in the right frame. */
1132 on_treeview1_button_press_event(GtkWidget * widget,
1133 GdkEventButton * event, gpointer user_data)
1135 GtkTreeView *view = GTK_TREE_VIEW(widget);
1137 GtkTreeViewColumn *column;
1141 gint tx = (gint) event->x;
1142 gint ty = (gint) event->y;
1145 gtk_tree_view_get_path_at_pos(view, tx, ty, &path, &column, &cx,
1150 gtk_tree_model_get_iter(model1, &iter, path);
1151 gtk_tree_model_get(model1, &iter, COL_MENU, &menu, -1);
1153 if (event->type == GDK_2BUTTON_PRESS) {
1154 toggle_sym_value(menu);
1156 display_tree_part();
1159 display_tree_part();
1162 gtk_widget_realize(tree2_w);
1163 gtk_tree_view_set_cursor(view, path, NULL, FALSE);
1164 gtk_widget_grab_focus(tree2_w);
1170 /* Fill a row of strings */
1171 static gchar **fill_row(struct menu *menu)
1173 static gchar *row[COL_NUMBER];
1174 struct symbol *sym = menu->sym;
1178 enum prop_type ptype;
1181 for (i = COL_OPTION; i <= COL_COLOR; i++)
1183 bzero(row, sizeof(row));
1186 g_strdup_printf("%s %s", menu_get_prompt(menu),
1187 sym && sym_has_value(sym) ? "(NEW)" : "");
1189 if (show_all && !menu_is_visible(menu))
1190 row[COL_COLOR] = g_strdup("DarkGray");
1192 row[COL_COLOR] = g_strdup("Black");
1194 ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
1197 row[COL_PIXBUF] = (gchar *) xpm_menu;
1198 if (view_mode == SINGLE_VIEW)
1199 row[COL_PIXVIS] = GINT_TO_POINTER(TRUE);
1200 row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
1203 row[COL_PIXBUF] = (gchar *) xpm_void;
1204 row[COL_PIXVIS] = GINT_TO_POINTER(FALSE);
1205 row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
1208 row[COL_PIXBUF] = (gchar *) xpm_void;
1209 row[COL_PIXVIS] = GINT_TO_POINTER(FALSE);
1210 row[COL_BTNVIS] = GINT_TO_POINTER(TRUE);
1216 row[COL_NAME] = g_strdup(sym->name);
1218 sym_calc_value(sym);
1219 sym->flags &= ~SYMBOL_CHANGED;
1221 if (sym_is_choice(sym)) { // parse childs for getting final value
1223 struct symbol *def_sym = sym_get_choice_value(sym);
1224 struct menu *def_menu = NULL;
1226 row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
1228 for (child = menu->list; child; child = child->next) {
1229 if (menu_is_visible(child)
1230 && child->sym == def_sym)
1236 g_strdup(menu_get_prompt(def_menu));
1238 if (sym->flags & SYMBOL_CHOICEVAL)
1239 row[COL_BTNRAD] = GINT_TO_POINTER(TRUE);
1241 stype = sym_get_type(sym);
1244 if (GPOINTER_TO_INT(row[COL_PIXVIS]) == FALSE)
1245 row[COL_BTNVIS] = GINT_TO_POINTER(TRUE);
1246 if (sym_is_choice(sym))
1249 val = sym_get_tristate_value(sym);
1252 row[COL_NO] = g_strdup("N");
1253 row[COL_VALUE] = g_strdup("N");
1254 row[COL_BTNACT] = GINT_TO_POINTER(FALSE);
1255 row[COL_BTNINC] = GINT_TO_POINTER(FALSE);
1258 row[COL_MOD] = g_strdup("M");
1259 row[COL_VALUE] = g_strdup("M");
1260 row[COL_BTNINC] = GINT_TO_POINTER(TRUE);
1263 row[COL_YES] = g_strdup("Y");
1264 row[COL_VALUE] = g_strdup("Y");
1265 row[COL_BTNACT] = GINT_TO_POINTER(TRUE);
1266 row[COL_BTNINC] = GINT_TO_POINTER(FALSE);
1270 if (val != no && sym_tristate_within_range(sym, no))
1271 row[COL_NO] = g_strdup("_");
1272 if (val != mod && sym_tristate_within_range(sym, mod))
1273 row[COL_MOD] = g_strdup("_");
1274 if (val != yes && sym_tristate_within_range(sym, yes))
1275 row[COL_YES] = g_strdup("_");
1280 def = sym_get_string_value(sym);
1281 row[COL_VALUE] = g_strdup(def);
1282 row[COL_EDIT] = GINT_TO_POINTER(TRUE);
1283 row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
1291 /* Set the node content with a row of strings */
1292 static void set_node(GtkTreeIter * node, struct menu *menu, gchar ** row)
1298 pix = gdk_pixbuf_new_from_xpm_data((const char **)
1301 gdk_color_parse(row[COL_COLOR], &color);
1302 gdk_colormap_alloc_colors(gdk_colormap_get_system(), &color, 1,
1303 FALSE, FALSE, &success);
1305 gtk_tree_store_set(tree, node,
1306 COL_OPTION, row[COL_OPTION],
1307 COL_NAME, row[COL_NAME],
1308 COL_NO, row[COL_NO],
1309 COL_MOD, row[COL_MOD],
1310 COL_YES, row[COL_YES],
1311 COL_VALUE, row[COL_VALUE],
1312 COL_MENU, (gpointer) menu,
1314 COL_EDIT, GPOINTER_TO_INT(row[COL_EDIT]),
1316 COL_PIXVIS, GPOINTER_TO_INT(row[COL_PIXVIS]),
1317 COL_BTNVIS, GPOINTER_TO_INT(row[COL_BTNVIS]),
1318 COL_BTNACT, GPOINTER_TO_INT(row[COL_BTNACT]),
1319 COL_BTNINC, GPOINTER_TO_INT(row[COL_BTNINC]),
1320 COL_BTNRAD, GPOINTER_TO_INT(row[COL_BTNRAD]),
1323 g_object_unref(pix);
1327 /* Add a node to the tree */
1328 static void place_node(struct menu *menu, char **row)
1330 GtkTreeIter *parent = parents[indent - 1];
1331 GtkTreeIter *node = parents[indent];
1333 gtk_tree_store_append(tree, node, parent);
1334 set_node(node, menu, row);
1338 /* Find a node in the GTK+ tree */
1339 static GtkTreeIter found;
1342 * Find a menu in the GtkTree starting at parent.
1344 GtkTreeIter *gtktree_iter_find_node(GtkTreeIter * parent,
1345 struct menu *tofind)
1348 GtkTreeIter *child = &iter;
1352 valid = gtk_tree_model_iter_children(model2, child, parent);
1356 gtk_tree_model_get(model2, child, 6, &menu, -1);
1358 if (menu == tofind) {
1359 memcpy(&found, child, sizeof(GtkTreeIter));
1363 ret = gtktree_iter_find_node(child, tofind);
1367 valid = gtk_tree_model_iter_next(model2, child);
1375 * Update the tree by adding/removing entries
1376 * Does not change other nodes
1378 static void update_tree(struct menu *src, GtkTreeIter * dst)
1380 struct menu *child1;
1381 GtkTreeIter iter, tmp;
1382 GtkTreeIter *child2 = &iter;
1384 GtkTreeIter *sibling;
1386 struct property *prop;
1387 struct menu *menu1, *menu2;
1389 if (src == &rootmenu)
1392 valid = gtk_tree_model_iter_children(model2, child2, dst);
1393 for (child1 = src->list; child1; child1 = child1->next) {
1395 prop = child1->prompt;
1401 gtk_tree_model_get(model2, child2, COL_MENU,
1404 menu2 = NULL; // force adding of a first child
1407 printf("%*c%s | %s\n", indent, ' ',
1408 menu1 ? menu_get_prompt(menu1) : "nil",
1409 menu2 ? menu_get_prompt(menu2) : "nil");
1412 if (!menu_is_visible(child1) && !show_all) { // remove node
1413 if (gtktree_iter_find_node(dst, menu1) != NULL) {
1414 memcpy(&tmp, child2, sizeof(GtkTreeIter));
1415 valid = gtk_tree_model_iter_next(model2,
1417 gtk_tree_store_remove(tree2, &tmp);
1419 return; // next parent
1421 goto reparse; // next child
1426 if (menu1 != menu2) {
1427 if (gtktree_iter_find_node(dst, menu1) == NULL) { // add node
1428 if (!valid && !menu2)
1432 gtk_tree_store_insert_before(tree2,
1435 set_node(child2, menu1, fill_row(menu1));
1438 } else { // remove node
1439 memcpy(&tmp, child2, sizeof(GtkTreeIter));
1440 valid = gtk_tree_model_iter_next(model2,
1442 gtk_tree_store_remove(tree2, &tmp);
1444 return; // next parent
1446 goto reparse; // next child
1448 } else if (sym && (sym->flags & SYMBOL_CHANGED)) {
1449 set_node(child2, menu1, fill_row(menu1));
1453 update_tree(child1, child2);
1456 valid = gtk_tree_model_iter_next(model2, child2);
1461 /* Display the whole tree (single/split/full view) */
1462 static void display_tree(struct menu *menu)
1465 struct property *prop;
1467 enum prop_type ptype;
1469 if (menu == &rootmenu) {
1471 current = &rootmenu;
1474 for (child = menu->list; child; child = child->next) {
1475 prop = child->prompt;
1477 ptype = prop ? prop->type : P_UNKNOWN;
1480 sym->flags &= ~SYMBOL_CHANGED;
1482 if ((view_mode == SPLIT_VIEW)
1483 && !(child->flags & MENU_ROOT) && (tree == tree1))
1486 if ((view_mode == SPLIT_VIEW) && (child->flags & MENU_ROOT)
1490 if (menu_is_visible(child) || show_all)
1491 place_node(child, fill_row(child));
1493 printf("%*c%s: ", indent, ' ', menu_get_prompt(child));
1494 printf("%s", child->flags & MENU_ROOT ? "rootmenu | " : "");
1495 dbg_print_ptype(ptype);
1498 dbg_print_stype(sym->type);
1500 dbg_print_flags(sym->flags);
1505 if ((view_mode != FULL_VIEW) && (ptype == P_MENU)
1509 if (((menu != &rootmenu) && !(menu->flags & MENU_ROOT))
1510 || (view_mode == FULL_VIEW)
1511 || (view_mode == SPLIT_VIEW))*/
1512 if (((view_mode == SINGLE_VIEW) && (menu->flags & MENU_ROOT))
1513 || (view_mode == FULL_VIEW)
1514 || (view_mode == SPLIT_VIEW)) {
1516 display_tree(child);
1522 /* Display a part of the tree starting at current node (single/split view) */
1523 static void display_tree_part(void)
1526 gtk_tree_store_clear(tree2);
1527 if (view_mode == SINGLE_VIEW)
1528 display_tree(current);
1529 else if (view_mode == SPLIT_VIEW)
1530 display_tree(browsed);
1531 gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w));
1534 /* Display the list in the left frame (split view) */
1535 static void display_list(void)
1538 gtk_tree_store_clear(tree1);
1541 display_tree(&rootmenu);
1542 gtk_tree_view_expand_all(GTK_TREE_VIEW(tree1_w));
1546 void fixup_rootmenu(struct menu *menu)
1549 static int menu_cnt = 0;
1551 menu->flags |= MENU_ROOT;
1552 for (child = menu->list; child; child = child->next) {
1553 if (child->prompt && child->prompt->type == P_MENU) {
1555 fixup_rootmenu(child);
1557 } else if (!menu_cnt)
1558 fixup_rootmenu(child);
1564 int main(int ac, char *av[])
1570 #ifndef LKC_DIRECT_LINK
1574 bindtextdomain(PACKAGE, LOCALEDIR);
1575 bind_textdomain_codeset(PACKAGE, "UTF-8");
1576 textdomain(PACKAGE);
1583 //add_pixmap_directory (PACKAGE_DATA_DIR "/" PACKAGE "/pixmaps");
1584 //add_pixmap_directory (PACKAGE_SOURCE_DIR "/pixmaps");
1586 /* Determine GUI path */
1587 env = getenv(SRCTREE);
1589 glade_file = g_strconcat(env, "/scripts/kconfig/gconf.glade", NULL);
1590 else if (av[0][0] == '/')
1591 glade_file = g_strconcat(av[0], ".glade", NULL);
1593 glade_file = g_strconcat(g_get_current_dir(), "/", av[0], ".glade", NULL);
1595 /* Load the interface and connect signals */
1596 init_main_window(glade_file);
1602 if (ac > 1 && av[1][0] == '-') {
1609 printf("%s <config>\n", av[0]);
1617 fixup_rootmenu(&rootmenu);
1620 switch (view_mode) {
1622 display_tree_part();
1628 display_tree(&rootmenu);