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, _("coreboot 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 /* Gettextize if the help text not empty */
465 if ((help != 0) && (help[0] != 0))
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_save_activate(GtkMenuItem * menuitem, gpointer user_data);
516 gboolean on_window1_delete_event(GtkWidget * widget, GdkEvent * event,
519 GtkWidget *dialog, *label;
522 if (!conf_get_changed())
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_save_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_save_activate(GtkMenuItem * menuitem, gpointer user_data)
626 if (conf_write(NULL))
627 text_insert_msg(_("Error"), _("Unable to save configuration !"));
628 if (conf_write_autoconf())
629 text_insert_msg(_("Error"), _("Unable to save configuration !"));
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 !"));
643 if (conf_write_autoconf())
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 configuration tool\n"
740 "For each option, a blank box indicates the feature is disabled, a\n"
741 "check indicates it is enabled, and a dot indicates that it is to\n"
742 "be compiled as a module. Clicking on the box will cycle through the three states.\n"
744 "If you do not see an option (e.g., a device driver) that you\n"
745 "believe should be present, try turning on Show All Options\n"
746 "under the Options menu.\n"
747 "Although there is no cross reference yet to help you figure out\n"
748 "what other options must be enabled to support the option you\n"
749 "are interested in, you can still view the help of a grayed-out\n"
752 "Toggling Show Debug Info under the Options menu will show \n"
753 "the dependencies, which you can then match by examining other options.");
755 dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
756 GTK_DIALOG_DESTROY_WITH_PARENT,
758 GTK_BUTTONS_CLOSE, intro_text);
759 g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
760 G_CALLBACK(gtk_widget_destroy),
762 gtk_widget_show_all(dialog);
766 void on_about1_activate(GtkMenuItem * menuitem, gpointer user_data)
769 const gchar *about_text =
770 _("gkc is copyright (c) 2002 Romain Lievin <roms@lpg.ticalc.org>.\n"
771 "Based on the source code from Roman Zippel.\n");
773 dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
774 GTK_DIALOG_DESTROY_WITH_PARENT,
776 GTK_BUTTONS_CLOSE, about_text);
777 g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
778 G_CALLBACK(gtk_widget_destroy),
780 gtk_widget_show_all(dialog);
784 void on_license1_activate(GtkMenuItem * menuitem, gpointer user_data)
787 const gchar *license_text =
788 _("gkc is released under the terms of the GNU GPL v2.\n"
789 "For more information, please see the source code or\n"
790 "visit http://www.fsf.org/licenses/licenses.html\n");
792 dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
793 GTK_DIALOG_DESTROY_WITH_PARENT,
795 GTK_BUTTONS_CLOSE, license_text);
796 g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
797 G_CALLBACK(gtk_widget_destroy),
799 gtk_widget_show_all(dialog);
803 void on_back_clicked(GtkButton * button, gpointer user_data)
805 enum prop_type ptype;
807 current = current->parent;
808 ptype = current->prompt ? current->prompt->type : P_UNKNOWN;
810 current = current->parent;
813 if (current == &rootmenu)
814 gtk_widget_set_sensitive(back_btn, FALSE);
818 void on_load_clicked(GtkButton * button, gpointer user_data)
820 on_load1_activate(NULL, user_data);
824 void on_single_clicked(GtkButton * button, gpointer user_data)
826 view_mode = SINGLE_VIEW;
827 gtk_paned_set_position(GTK_PANED(hpaned), 0);
828 gtk_widget_hide(tree1_w);
834 void on_split_clicked(GtkButton * button, gpointer user_data)
837 view_mode = SPLIT_VIEW;
838 gtk_widget_show(tree1_w);
839 gtk_window_get_default_size(GTK_WINDOW(main_wnd), &w, &h);
840 gtk_paned_set_position(GTK_PANED(hpaned), w / 2);
842 gtk_tree_store_clear(tree2);
845 /* Disable back btn, like in full mode. */
846 gtk_widget_set_sensitive(back_btn, FALSE);
850 void on_full_clicked(GtkButton * button, gpointer user_data)
852 view_mode = FULL_VIEW;
853 gtk_paned_set_position(GTK_PANED(hpaned), 0);
854 gtk_widget_hide(tree1_w);
856 gtk_tree_store_clear(tree2);
857 display_tree(&rootmenu);
858 gtk_widget_set_sensitive(back_btn, FALSE);
862 void on_collapse_clicked(GtkButton * button, gpointer user_data)
864 gtk_tree_view_collapse_all(GTK_TREE_VIEW(tree2_w));
868 void on_expand_clicked(GtkButton * button, gpointer user_data)
870 gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w));
874 /* CTree Callbacks */
876 /* Change hex/int/string value in the cell */
877 static void renderer_edited(GtkCellRendererText * cell,
878 const gchar * path_string,
879 const gchar * new_text, gpointer user_data)
881 GtkTreePath *path = gtk_tree_path_new_from_string(path_string);
883 const char *old_def, *new_def;
887 if (!gtk_tree_model_get_iter(model2, &iter, path))
890 gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
893 gtk_tree_model_get(model2, &iter, COL_VALUE, &old_def, -1);
896 sym_set_string_value(sym, new_def);
898 update_tree(&rootmenu, NULL);
900 gtk_tree_path_free(path);
903 /* Change the value of a symbol and update the tree */
904 static void change_sym_value(struct menu *menu, gint col)
906 struct symbol *sym = menu->sym;
907 tristate oldval, newval;
914 else if (col == COL_MOD)
916 else if (col == COL_YES)
921 switch (sym_get_type(sym)) {
924 oldval = sym_get_tristate_value(sym);
925 if (!sym_tristate_within_range(sym, newval))
927 sym_set_tristate_value(sym, newval);
928 if (view_mode == FULL_VIEW)
929 update_tree(&rootmenu, NULL);
930 else if (view_mode == SPLIT_VIEW) {
931 update_tree(browsed, NULL);
934 else if (view_mode == SINGLE_VIEW)
935 display_tree_part(); //fixme: keep exp/coll
945 static void toggle_sym_value(struct menu *menu)
950 sym_toggle_tristate_value(menu->sym);
951 if (view_mode == FULL_VIEW)
952 update_tree(&rootmenu, NULL);
953 else if (view_mode == SPLIT_VIEW) {
954 update_tree(browsed, NULL);
957 else if (view_mode == SINGLE_VIEW)
958 display_tree_part(); //fixme: keep exp/coll
961 static void renderer_toggled(GtkCellRendererToggle * cell,
962 gchar * path_string, gpointer user_data)
964 GtkTreePath *path, *sel_path = NULL;
965 GtkTreeIter iter, sel_iter;
966 GtkTreeSelection *sel;
969 path = gtk_tree_path_new_from_string(path_string);
970 if (!gtk_tree_model_get_iter(model2, &iter, path))
973 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree2_w));
974 if (gtk_tree_selection_get_selected(sel, NULL, &sel_iter))
975 sel_path = gtk_tree_model_get_path(model2, &sel_iter);
978 if (gtk_tree_path_compare(path, sel_path))
981 gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
982 toggle_sym_value(menu);
985 gtk_tree_path_free(sel_path);
987 gtk_tree_path_free(path);
990 static gint column2index(GtkTreeViewColumn * column)
994 for (i = 0; i < COL_NUMBER; i++) {
995 GtkTreeViewColumn *col;
997 col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), i);
1006 /* User click: update choice (full) or goes down (single) */
1008 on_treeview2_button_press_event(GtkWidget * widget,
1009 GdkEventButton * event, gpointer user_data)
1011 GtkTreeView *view = GTK_TREE_VIEW(widget);
1013 GtkTreeViewColumn *column;
1018 #if GTK_CHECK_VERSION(2,1,4) // bug in ctree with earlier version of GTK
1019 gint tx = (gint) event->x;
1020 gint ty = (gint) event->y;
1023 gtk_tree_view_get_path_at_pos(view, tx, ty, &path, &column, &cx,
1026 gtk_tree_view_get_cursor(view, &path, &column);
1031 if (!gtk_tree_model_get_iter(model2, &iter, path))
1033 gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
1035 col = column2index(column);
1036 if (event->type == GDK_2BUTTON_PRESS) {
1037 enum prop_type ptype;
1038 ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
1040 if (ptype == P_MENU && view_mode != FULL_VIEW && col == COL_OPTION) {
1041 // goes down into menu
1043 display_tree_part();
1044 gtk_widget_set_sensitive(back_btn, TRUE);
1045 } else if ((col == COL_OPTION)) {
1046 toggle_sym_value(menu);
1047 gtk_tree_view_expand_row(view, path, TRUE);
1050 if (col == COL_VALUE) {
1051 toggle_sym_value(menu);
1052 gtk_tree_view_expand_row(view, path, TRUE);
1053 } else if (col == COL_NO || col == COL_MOD
1054 || col == COL_YES) {
1055 change_sym_value(menu, col);
1056 gtk_tree_view_expand_row(view, path, TRUE);
1063 /* Key pressed: update choice */
1065 on_treeview2_key_press_event(GtkWidget * widget,
1066 GdkEventKey * event, gpointer user_data)
1068 GtkTreeView *view = GTK_TREE_VIEW(widget);
1070 GtkTreeViewColumn *column;
1075 gtk_tree_view_get_cursor(view, &path, &column);
1079 if (event->keyval == GDK_space) {
1080 if (gtk_tree_view_row_expanded(view, path))
1081 gtk_tree_view_collapse_row(view, path);
1083 gtk_tree_view_expand_row(view, path, FALSE);
1086 if (event->keyval == GDK_KP_Enter) {
1088 if (widget == tree1_w)
1091 gtk_tree_model_get_iter(model2, &iter, path);
1092 gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
1094 if (!strcasecmp(event->string, "n"))
1096 else if (!strcasecmp(event->string, "m"))
1098 else if (!strcasecmp(event->string, "y"))
1102 change_sym_value(menu, col);
1108 /* Row selection changed: update help */
1110 on_treeview2_cursor_changed(GtkTreeView * treeview, gpointer user_data)
1112 GtkTreeSelection *selection;
1116 selection = gtk_tree_view_get_selection(treeview);
1117 if (gtk_tree_selection_get_selected(selection, &model2, &iter)) {
1118 gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
1119 text_insert_help(menu);
1124 /* User click: display sub-tree in the right frame. */
1126 on_treeview1_button_press_event(GtkWidget * widget,
1127 GdkEventButton * event, gpointer user_data)
1129 GtkTreeView *view = GTK_TREE_VIEW(widget);
1131 GtkTreeViewColumn *column;
1135 gint tx = (gint) event->x;
1136 gint ty = (gint) event->y;
1139 gtk_tree_view_get_path_at_pos(view, tx, ty, &path, &column, &cx,
1144 gtk_tree_model_get_iter(model1, &iter, path);
1145 gtk_tree_model_get(model1, &iter, COL_MENU, &menu, -1);
1147 if (event->type == GDK_2BUTTON_PRESS) {
1148 toggle_sym_value(menu);
1150 display_tree_part();
1153 display_tree_part();
1156 gtk_widget_realize(tree2_w);
1157 gtk_tree_view_set_cursor(view, path, NULL, FALSE);
1158 gtk_widget_grab_focus(tree2_w);
1164 /* Fill a row of strings */
1165 static gchar **fill_row(struct menu *menu)
1167 static gchar *row[COL_NUMBER];
1168 struct symbol *sym = menu->sym;
1172 enum prop_type ptype;
1175 for (i = COL_OPTION; i <= COL_COLOR; i++)
1177 bzero(row, sizeof(row));
1180 g_strdup_printf("%s %s", _(menu_get_prompt(menu)),
1181 sym && sym_has_value(sym) ? "(NEW)" : "");
1183 if (show_all && !menu_is_visible(menu))
1184 row[COL_COLOR] = g_strdup("DarkGray");
1186 row[COL_COLOR] = g_strdup("Black");
1188 ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
1191 row[COL_PIXBUF] = (gchar *) xpm_menu;
1192 if (view_mode == SINGLE_VIEW)
1193 row[COL_PIXVIS] = GINT_TO_POINTER(TRUE);
1194 row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
1197 row[COL_PIXBUF] = (gchar *) xpm_void;
1198 row[COL_PIXVIS] = GINT_TO_POINTER(FALSE);
1199 row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
1202 row[COL_PIXBUF] = (gchar *) xpm_void;
1203 row[COL_PIXVIS] = GINT_TO_POINTER(FALSE);
1204 row[COL_BTNVIS] = GINT_TO_POINTER(TRUE);
1210 row[COL_NAME] = g_strdup(sym->name);
1212 sym_calc_value(sym);
1213 sym->flags &= ~SYMBOL_CHANGED;
1215 if (sym_is_choice(sym)) { // parse childs for getting final value
1217 struct symbol *def_sym = sym_get_choice_value(sym);
1218 struct menu *def_menu = NULL;
1220 row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
1222 for (child = menu->list; child; child = child->next) {
1223 if (menu_is_visible(child)
1224 && child->sym == def_sym)
1230 g_strdup(_(menu_get_prompt(def_menu)));
1232 if (sym->flags & SYMBOL_CHOICEVAL)
1233 row[COL_BTNRAD] = GINT_TO_POINTER(TRUE);
1235 stype = sym_get_type(sym);
1238 if (GPOINTER_TO_INT(row[COL_PIXVIS]) == FALSE)
1239 row[COL_BTNVIS] = GINT_TO_POINTER(TRUE);
1240 if (sym_is_choice(sym))
1243 val = sym_get_tristate_value(sym);
1246 row[COL_NO] = g_strdup("N");
1247 row[COL_VALUE] = g_strdup("N");
1248 row[COL_BTNACT] = GINT_TO_POINTER(FALSE);
1249 row[COL_BTNINC] = GINT_TO_POINTER(FALSE);
1252 row[COL_MOD] = g_strdup("M");
1253 row[COL_VALUE] = g_strdup("M");
1254 row[COL_BTNINC] = GINT_TO_POINTER(TRUE);
1257 row[COL_YES] = g_strdup("Y");
1258 row[COL_VALUE] = g_strdup("Y");
1259 row[COL_BTNACT] = GINT_TO_POINTER(TRUE);
1260 row[COL_BTNINC] = GINT_TO_POINTER(FALSE);
1264 if (val != no && sym_tristate_within_range(sym, no))
1265 row[COL_NO] = g_strdup("_");
1266 if (val != mod && sym_tristate_within_range(sym, mod))
1267 row[COL_MOD] = g_strdup("_");
1268 if (val != yes && sym_tristate_within_range(sym, yes))
1269 row[COL_YES] = g_strdup("_");
1274 def = sym_get_string_value(sym);
1275 row[COL_VALUE] = g_strdup(def);
1276 row[COL_EDIT] = GINT_TO_POINTER(TRUE);
1277 row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
1285 /* Set the node content with a row of strings */
1286 static void set_node(GtkTreeIter * node, struct menu *menu, gchar ** row)
1292 pix = gdk_pixbuf_new_from_xpm_data((const char **)
1295 gdk_color_parse(row[COL_COLOR], &color);
1296 gdk_colormap_alloc_colors(gdk_colormap_get_system(), &color, 1,
1297 FALSE, FALSE, &success);
1299 gtk_tree_store_set(tree, node,
1300 COL_OPTION, row[COL_OPTION],
1301 COL_NAME, row[COL_NAME],
1302 COL_NO, row[COL_NO],
1303 COL_MOD, row[COL_MOD],
1304 COL_YES, row[COL_YES],
1305 COL_VALUE, row[COL_VALUE],
1306 COL_MENU, (gpointer) menu,
1308 COL_EDIT, GPOINTER_TO_INT(row[COL_EDIT]),
1310 COL_PIXVIS, GPOINTER_TO_INT(row[COL_PIXVIS]),
1311 COL_BTNVIS, GPOINTER_TO_INT(row[COL_BTNVIS]),
1312 COL_BTNACT, GPOINTER_TO_INT(row[COL_BTNACT]),
1313 COL_BTNINC, GPOINTER_TO_INT(row[COL_BTNINC]),
1314 COL_BTNRAD, GPOINTER_TO_INT(row[COL_BTNRAD]),
1317 g_object_unref(pix);
1321 /* Add a node to the tree */
1322 static void place_node(struct menu *menu, char **row)
1324 GtkTreeIter *parent = parents[indent - 1];
1325 GtkTreeIter *node = parents[indent];
1327 gtk_tree_store_append(tree, node, parent);
1328 set_node(node, menu, row);
1332 /* Find a node in the GTK+ tree */
1333 static GtkTreeIter found;
1336 * Find a menu in the GtkTree starting at parent.
1338 GtkTreeIter *gtktree_iter_find_node(GtkTreeIter * parent,
1339 struct menu *tofind)
1342 GtkTreeIter *child = &iter;
1346 valid = gtk_tree_model_iter_children(model2, child, parent);
1350 gtk_tree_model_get(model2, child, 6, &menu, -1);
1352 if (menu == tofind) {
1353 memcpy(&found, child, sizeof(GtkTreeIter));
1357 ret = gtktree_iter_find_node(child, tofind);
1361 valid = gtk_tree_model_iter_next(model2, child);
1369 * Update the tree by adding/removing entries
1370 * Does not change other nodes
1372 static void update_tree(struct menu *src, GtkTreeIter * dst)
1374 struct menu *child1;
1375 GtkTreeIter iter, tmp;
1376 GtkTreeIter *child2 = &iter;
1378 GtkTreeIter *sibling;
1380 struct property *prop;
1381 struct menu *menu1, *menu2;
1383 if (src == &rootmenu)
1386 valid = gtk_tree_model_iter_children(model2, child2, dst);
1387 for (child1 = src->list; child1; child1 = child1->next) {
1389 prop = child1->prompt;
1395 gtk_tree_model_get(model2, child2, COL_MENU,
1398 menu2 = NULL; // force adding of a first child
1401 printf("%*c%s | %s\n", indent, ' ',
1402 menu1 ? menu_get_prompt(menu1) : "nil",
1403 menu2 ? menu_get_prompt(menu2) : "nil");
1406 if (!menu_is_visible(child1) && !show_all) { // remove node
1407 if (gtktree_iter_find_node(dst, menu1) != NULL) {
1408 memcpy(&tmp, child2, sizeof(GtkTreeIter));
1409 valid = gtk_tree_model_iter_next(model2,
1411 gtk_tree_store_remove(tree2, &tmp);
1413 return; // next parent
1415 goto reparse; // next child
1420 if (menu1 != menu2) {
1421 if (gtktree_iter_find_node(dst, menu1) == NULL) { // add node
1422 if (!valid && !menu2)
1426 gtk_tree_store_insert_before(tree2,
1429 set_node(child2, menu1, fill_row(menu1));
1432 } else { // remove node
1433 memcpy(&tmp, child2, sizeof(GtkTreeIter));
1434 valid = gtk_tree_model_iter_next(model2,
1436 gtk_tree_store_remove(tree2, &tmp);
1438 return; // next parent
1440 goto reparse; // next child
1442 } else if (sym && (sym->flags & SYMBOL_CHANGED)) {
1443 set_node(child2, menu1, fill_row(menu1));
1447 update_tree(child1, child2);
1450 valid = gtk_tree_model_iter_next(model2, child2);
1455 /* Display the whole tree (single/split/full view) */
1456 static void display_tree(struct menu *menu)
1459 struct property *prop;
1461 enum prop_type ptype;
1463 if (menu == &rootmenu) {
1465 current = &rootmenu;
1468 for (child = menu->list; child; child = child->next) {
1469 prop = child->prompt;
1471 ptype = prop ? prop->type : P_UNKNOWN;
1474 sym->flags &= ~SYMBOL_CHANGED;
1476 if ((view_mode == SPLIT_VIEW)
1477 && !(child->flags & MENU_ROOT) && (tree == tree1))
1480 if ((view_mode == SPLIT_VIEW) && (child->flags & MENU_ROOT)
1484 if (menu_is_visible(child) || show_all)
1485 place_node(child, fill_row(child));
1487 printf("%*c%s: ", indent, ' ', menu_get_prompt(child));
1488 printf("%s", child->flags & MENU_ROOT ? "rootmenu | " : "");
1489 dbg_print_ptype(ptype);
1492 dbg_print_stype(sym->type);
1494 dbg_print_flags(sym->flags);
1499 if ((view_mode != FULL_VIEW) && (ptype == P_MENU)
1503 if (((menu != &rootmenu) && !(menu->flags & MENU_ROOT))
1504 || (view_mode == FULL_VIEW)
1505 || (view_mode == SPLIT_VIEW))*/
1506 if (((view_mode == SINGLE_VIEW) && (menu->flags & MENU_ROOT))
1507 || (view_mode == FULL_VIEW)
1508 || (view_mode == SPLIT_VIEW)) {
1510 display_tree(child);
1516 /* Display a part of the tree starting at current node (single/split view) */
1517 static void display_tree_part(void)
1520 gtk_tree_store_clear(tree2);
1521 if (view_mode == SINGLE_VIEW)
1522 display_tree(current);
1523 else if (view_mode == SPLIT_VIEW)
1524 display_tree(browsed);
1525 gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w));
1528 /* Display the list in the left frame (split view) */
1529 static void display_list(void)
1532 gtk_tree_store_clear(tree1);
1535 display_tree(&rootmenu);
1536 gtk_tree_view_expand_all(GTK_TREE_VIEW(tree1_w));
1540 void fixup_rootmenu(struct menu *menu)
1543 static int menu_cnt = 0;
1545 menu->flags |= MENU_ROOT;
1546 for (child = menu->list; child; child = child->next) {
1547 if (child->prompt && child->prompt->type == P_MENU) {
1549 fixup_rootmenu(child);
1551 } else if (!menu_cnt)
1552 fixup_rootmenu(child);
1558 int main(int ac, char *av[])
1564 #ifndef LKC_DIRECT_LINK
1568 bindtextdomain(PACKAGE, LOCALEDIR);
1569 bind_textdomain_codeset(PACKAGE, "UTF-8");
1570 textdomain(PACKAGE);
1577 //add_pixmap_directory (PACKAGE_DATA_DIR "/" PACKAGE "/pixmaps");
1578 //add_pixmap_directory (PACKAGE_SOURCE_DIR "/pixmaps");
1580 /* Determine GUI path */
1581 env = getenv(SRCTREE);
1583 glade_file = g_strconcat(env, "/util/kconfig/gconf.glade", NULL);
1584 else if (av[0][0] == '/')
1585 glade_file = g_strconcat(av[0], ".glade", NULL);
1587 glade_file = g_strconcat(g_get_current_dir(), "/", av[0], ".glade", NULL);
1589 /* Load the interface and connect signals */
1590 init_main_window(glade_file);
1596 if (ac > 1 && av[1][0] == '-') {
1603 printf("%s <config>\n", av[0]);
1611 fixup_rootmenu(&rootmenu);
1614 switch (view_mode) {
1616 display_tree_part();
1622 display_tree(&rootmenu);
1631 static void conf_changed(void)
1633 bool changed = conf_get_changed();
1634 gtk_widget_set_sensitive(save_btn, changed);
1635 gtk_widget_set_sensitive(save_menu_item, changed);