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
34 OPT_NORMAL, OPT_ALL, OPT_PROMPT
37 static gint view_mode = FULL_VIEW;
38 static gboolean show_name = TRUE;
39 static gboolean show_range = TRUE;
40 static gboolean show_value = TRUE;
41 static gboolean resizeable = FALSE;
42 static int opt_mode = OPT_NORMAL;
44 GtkWidget *main_wnd = NULL;
45 GtkWidget *tree1_w = NULL; // left frame
46 GtkWidget *tree2_w = NULL; // right frame
47 GtkWidget *text_w = NULL;
48 GtkWidget *hpaned = NULL;
49 GtkWidget *vpaned = NULL;
50 GtkWidget *back_btn = NULL;
51 GtkWidget *save_btn = NULL;
52 GtkWidget *save_menu_item = NULL;
54 GtkTextTag *tag1, *tag2;
57 GtkTreeStore *tree1, *tree2, *tree;
58 GtkTreeModel *model1, *model2;
59 static GtkTreeIter *parents[256];
62 static struct menu *current; // current node for SINGLE view
63 static struct menu *browsed; // browsed node for SPLIT view
66 COL_OPTION, COL_NAME, COL_NO, COL_MOD, COL_YES, COL_VALUE,
67 COL_MENU, COL_COLOR, COL_EDIT, COL_PIXBUF,
68 COL_PIXVIS, COL_BTNVIS, COL_BTNACT, COL_BTNINC, COL_BTNRAD,
72 static void display_list(void);
73 static void display_tree(struct menu *menu);
74 static void display_tree_part(void);
75 static void update_tree(struct menu *src, GtkTreeIter * dst);
76 static void set_node(GtkTreeIter * node, struct menu *menu, gchar ** row);
77 static gchar **fill_row(struct menu *menu);
78 static void conf_changed(void);
80 /* Helping/Debugging Functions */
82 const char *dbg_sym_flags(int val)
88 if (val & SYMBOL_CONST)
89 strcat(buf, "const/");
90 if (val & SYMBOL_CHECK)
91 strcat(buf, "check/");
92 if (val & SYMBOL_CHOICE)
93 strcat(buf, "choice/");
94 if (val & SYMBOL_CHOICEVAL)
95 strcat(buf, "choiceval/");
96 if (val & SYMBOL_VALID)
97 strcat(buf, "valid/");
98 if (val & SYMBOL_OPTIONAL)
99 strcat(buf, "optional/");
100 if (val & SYMBOL_WRITE)
101 strcat(buf, "write/");
102 if (val & SYMBOL_CHANGED)
103 strcat(buf, "changed/");
104 if (val & SYMBOL_AUTO)
105 strcat(buf, "auto/");
107 buf[strlen(buf) - 1] = '\0';
112 void replace_button_icon(GladeXML * xml, GdkDrawable * window,
113 GtkStyle * style, gchar * btn_name, gchar ** xpm)
117 GtkToolButton *button;
120 pixmap = gdk_pixmap_create_from_xpm_d(window, &mask,
121 &style->bg[GTK_STATE_NORMAL],
124 button = GTK_TOOL_BUTTON(glade_xml_get_widget(xml, btn_name));
125 image = gtk_image_new_from_pixmap(pixmap, mask);
126 gtk_widget_show(image);
127 gtk_tool_button_set_icon_widget(button, image);
130 /* Main Window Initialization */
131 void init_main_window(const gchar * glade_file)
135 GtkTextBuffer *txtbuf;
139 xml = glade_xml_new(glade_file, "window1", NULL);
141 g_error(_("GUI loading failed !\n"));
142 glade_xml_signal_autoconnect(xml);
144 main_wnd = glade_xml_get_widget(xml, "window1");
145 hpaned = glade_xml_get_widget(xml, "hpaned1");
146 vpaned = glade_xml_get_widget(xml, "vpaned1");
147 tree1_w = glade_xml_get_widget(xml, "treeview1");
148 tree2_w = glade_xml_get_widget(xml, "treeview2");
149 text_w = glade_xml_get_widget(xml, "textview3");
151 back_btn = glade_xml_get_widget(xml, "button1");
152 gtk_widget_set_sensitive(back_btn, FALSE);
154 widget = glade_xml_get_widget(xml, "show_name1");
155 gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget,
158 widget = glade_xml_get_widget(xml, "show_range1");
159 gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget,
162 widget = glade_xml_get_widget(xml, "show_data1");
163 gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget,
166 save_btn = glade_xml_get_widget(xml, "button3");
167 save_menu_item = glade_xml_get_widget(xml, "save1");
168 conf_set_changed_callback(conf_changed);
170 style = gtk_widget_get_style(main_wnd);
171 widget = glade_xml_get_widget(xml, "toolbar1");
173 #if 0 /* Use stock Gtk icons instead */
174 replace_button_icon(xml, main_wnd->window, style,
175 "button1", (gchar **) xpm_back);
176 replace_button_icon(xml, main_wnd->window, style,
177 "button2", (gchar **) xpm_load);
178 replace_button_icon(xml, main_wnd->window, style,
179 "button3", (gchar **) xpm_save);
181 replace_button_icon(xml, main_wnd->window, style,
182 "button4", (gchar **) xpm_single_view);
183 replace_button_icon(xml, main_wnd->window, style,
184 "button5", (gchar **) xpm_split_view);
185 replace_button_icon(xml, main_wnd->window, style,
186 "button6", (gchar **) xpm_tree_view);
191 widget = glade_xml_get_widget(xml, "button4");
192 g_signal_emit_by_name(widget, "clicked");
195 widget = glade_xml_get_widget(xml, "button5");
196 g_signal_emit_by_name(widget, "clicked");
199 widget = glade_xml_get_widget(xml, "button6");
200 g_signal_emit_by_name(widget, "clicked");
204 txtbuf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w));
205 tag1 = gtk_text_buffer_create_tag(txtbuf, "mytag1",
207 "weight", PANGO_WEIGHT_BOLD,
209 tag2 = gtk_text_buffer_create_tag(txtbuf, "mytag2",
210 /*"style", PANGO_STYLE_OBLIQUE, */
213 sprintf(title, _("Linux Kernel v%s Configuration"),
214 getenv("KERNELVERSION"));
215 gtk_window_set_title(GTK_WINDOW(main_wnd), title);
217 gtk_widget_show(main_wnd);
220 void init_tree_model(void)
224 tree = tree2 = gtk_tree_store_new(COL_NUMBER,
225 G_TYPE_STRING, G_TYPE_STRING,
226 G_TYPE_STRING, G_TYPE_STRING,
227 G_TYPE_STRING, G_TYPE_STRING,
228 G_TYPE_POINTER, GDK_TYPE_COLOR,
229 G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF,
230 G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
231 G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
233 model2 = GTK_TREE_MODEL(tree2);
235 for (parents[0] = NULL, i = 1; i < 256; i++)
236 parents[i] = (GtkTreeIter *) g_malloc(sizeof(GtkTreeIter));
238 tree1 = gtk_tree_store_new(COL_NUMBER,
239 G_TYPE_STRING, G_TYPE_STRING,
240 G_TYPE_STRING, G_TYPE_STRING,
241 G_TYPE_STRING, G_TYPE_STRING,
242 G_TYPE_POINTER, GDK_TYPE_COLOR,
243 G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF,
244 G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
245 G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
247 model1 = GTK_TREE_MODEL(tree1);
250 void init_left_tree(void)
252 GtkTreeView *view = GTK_TREE_VIEW(tree1_w);
253 GtkCellRenderer *renderer;
254 GtkTreeSelection *sel;
255 GtkTreeViewColumn *column;
257 gtk_tree_view_set_model(view, model1);
258 gtk_tree_view_set_headers_visible(view, TRUE);
259 gtk_tree_view_set_rules_hint(view, FALSE);
261 column = gtk_tree_view_column_new();
262 gtk_tree_view_append_column(view, column);
263 gtk_tree_view_column_set_title(column, _("Options"));
265 renderer = gtk_cell_renderer_toggle_new();
266 gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
268 gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
270 "active", COL_BTNACT,
271 "inconsistent", COL_BTNINC,
272 "visible", COL_BTNVIS,
273 "radio", COL_BTNRAD, NULL);
274 renderer = gtk_cell_renderer_text_new();
275 gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
277 gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
283 sel = gtk_tree_view_get_selection(view);
284 gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
285 gtk_widget_realize(tree1_w);
288 static void renderer_edited(GtkCellRendererText * cell,
289 const gchar * path_string,
290 const gchar * new_text, gpointer user_data);
291 static void renderer_toggled(GtkCellRendererToggle * cellrenderertoggle,
292 gchar * arg1, gpointer user_data);
294 void init_right_tree(void)
296 GtkTreeView *view = GTK_TREE_VIEW(tree2_w);
297 GtkCellRenderer *renderer;
298 GtkTreeSelection *sel;
299 GtkTreeViewColumn *column;
302 gtk_tree_view_set_model(view, model2);
303 gtk_tree_view_set_headers_visible(view, TRUE);
304 gtk_tree_view_set_rules_hint(view, FALSE);
306 column = gtk_tree_view_column_new();
307 gtk_tree_view_append_column(view, column);
308 gtk_tree_view_column_set_title(column, _("Options"));
310 renderer = gtk_cell_renderer_pixbuf_new();
311 gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
313 gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
315 "pixbuf", COL_PIXBUF,
316 "visible", COL_PIXVIS, NULL);
317 renderer = gtk_cell_renderer_toggle_new();
318 gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
320 gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
322 "active", COL_BTNACT,
323 "inconsistent", COL_BTNINC,
324 "visible", COL_BTNVIS,
325 "radio", COL_BTNRAD, NULL);
326 /*g_signal_connect(G_OBJECT(renderer), "toggled",
327 G_CALLBACK(renderer_toggled), NULL); */
328 renderer = gtk_cell_renderer_text_new();
329 gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
331 gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
337 renderer = gtk_cell_renderer_text_new();
338 gtk_tree_view_insert_column_with_attributes(view, -1,
343 renderer = gtk_cell_renderer_text_new();
344 gtk_tree_view_insert_column_with_attributes(view, -1,
349 renderer = gtk_cell_renderer_text_new();
350 gtk_tree_view_insert_column_with_attributes(view, -1,
355 renderer = gtk_cell_renderer_text_new();
356 gtk_tree_view_insert_column_with_attributes(view, -1,
361 renderer = gtk_cell_renderer_text_new();
362 gtk_tree_view_insert_column_with_attributes(view, -1,
363 _("Value"), renderer,
369 g_signal_connect(G_OBJECT(renderer), "edited",
370 G_CALLBACK(renderer_edited), NULL);
372 column = gtk_tree_view_get_column(view, COL_NAME);
373 gtk_tree_view_column_set_visible(column, show_name);
374 column = gtk_tree_view_get_column(view, COL_NO);
375 gtk_tree_view_column_set_visible(column, show_range);
376 column = gtk_tree_view_get_column(view, COL_MOD);
377 gtk_tree_view_column_set_visible(column, show_range);
378 column = gtk_tree_view_get_column(view, COL_YES);
379 gtk_tree_view_column_set_visible(column, show_range);
380 column = gtk_tree_view_get_column(view, COL_VALUE);
381 gtk_tree_view_column_set_visible(column, show_value);
384 for (i = 0; i < COL_VALUE; i++) {
385 column = gtk_tree_view_get_column(view, i);
386 gtk_tree_view_column_set_resizable(column, TRUE);
390 sel = gtk_tree_view_get_selection(view);
391 gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
395 /* Utility Functions */
398 static void text_insert_help(struct menu *menu)
400 GtkTextBuffer *buffer;
401 GtkTextIter start, end;
402 const char *prompt = _(menu_get_prompt(menu));
403 struct gstr help = str_new();
405 menu_get_ext_help(menu, &help);
407 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w));
408 gtk_text_buffer_get_bounds(buffer, &start, &end);
409 gtk_text_buffer_delete(buffer, &start, &end);
410 gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_w), 15);
412 gtk_text_buffer_get_end_iter(buffer, &end);
413 gtk_text_buffer_insert_with_tags(buffer, &end, prompt, -1, tag1,
415 gtk_text_buffer_insert_at_cursor(buffer, "\n\n", 2);
416 gtk_text_buffer_get_end_iter(buffer, &end);
417 gtk_text_buffer_insert_with_tags(buffer, &end, str_get(&help), -1, tag2,
423 static void text_insert_msg(const char *title, const char *message)
425 GtkTextBuffer *buffer;
426 GtkTextIter start, end;
427 const char *msg = message;
429 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w));
430 gtk_text_buffer_get_bounds(buffer, &start, &end);
431 gtk_text_buffer_delete(buffer, &start, &end);
432 gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_w), 15);
434 gtk_text_buffer_get_end_iter(buffer, &end);
435 gtk_text_buffer_insert_with_tags(buffer, &end, title, -1, tag1,
437 gtk_text_buffer_insert_at_cursor(buffer, "\n\n", 2);
438 gtk_text_buffer_get_end_iter(buffer, &end);
439 gtk_text_buffer_insert_with_tags(buffer, &end, msg, -1, tag2,
444 /* Main Windows Callbacks */
446 void on_save_activate(GtkMenuItem * menuitem, gpointer user_data);
447 gboolean on_window1_delete_event(GtkWidget * widget, GdkEvent * event,
450 GtkWidget *dialog, *label;
453 if (!conf_get_changed())
456 dialog = gtk_dialog_new_with_buttons(_("Warning !"),
457 GTK_WINDOW(main_wnd),
460 GTK_DIALOG_DESTROY_WITH_PARENT),
466 GTK_RESPONSE_CANCEL, NULL);
467 gtk_dialog_set_default_response(GTK_DIALOG(dialog),
468 GTK_RESPONSE_CANCEL);
470 label = gtk_label_new(_("\nSave configuration ?\n"));
471 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), label);
472 gtk_widget_show(label);
474 result = gtk_dialog_run(GTK_DIALOG(dialog));
476 case GTK_RESPONSE_YES:
477 on_save_activate(NULL, NULL);
479 case GTK_RESPONSE_NO:
481 case GTK_RESPONSE_CANCEL:
482 case GTK_RESPONSE_DELETE_EVENT:
484 gtk_widget_destroy(dialog);
492 void on_window1_destroy(GtkObject * object, gpointer user_data)
499 on_window1_size_request(GtkWidget * widget,
500 GtkRequisition * requisition, gpointer user_data)
505 if (widget->window == NULL)
506 gtk_window_get_default_size(GTK_WINDOW(main_wnd), &w, &h);
508 gdk_window_get_size(widget->window, &w, &h);
514 gtk_paned_set_position(GTK_PANED(vpaned), 2 * h / 3);
518 /* Menu & Toolbar Callbacks */
522 load_filename(GtkFileSelection * file_selector, gpointer user_data)
526 fn = gtk_file_selection_get_filename(GTK_FILE_SELECTION
530 text_insert_msg(_("Error"), _("Unable to load configuration !"));
532 display_tree(&rootmenu);
535 void on_load1_activate(GtkMenuItem * menuitem, gpointer user_data)
539 fs = gtk_file_selection_new(_("Load file..."));
540 g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs)->ok_button),
542 G_CALLBACK(load_filename), (gpointer) fs);
543 g_signal_connect_swapped(GTK_OBJECT
544 (GTK_FILE_SELECTION(fs)->ok_button),
545 "clicked", G_CALLBACK(gtk_widget_destroy),
547 g_signal_connect_swapped(GTK_OBJECT
548 (GTK_FILE_SELECTION(fs)->cancel_button),
549 "clicked", G_CALLBACK(gtk_widget_destroy),
555 void on_save_activate(GtkMenuItem * menuitem, gpointer user_data)
557 if (conf_write(NULL))
558 text_insert_msg(_("Error"), _("Unable to save configuration !"));
563 store_filename(GtkFileSelection * file_selector, gpointer user_data)
567 fn = gtk_file_selection_get_filename(GTK_FILE_SELECTION
571 text_insert_msg(_("Error"), _("Unable to save configuration !"));
573 gtk_widget_destroy(GTK_WIDGET(user_data));
576 void on_save_as1_activate(GtkMenuItem * menuitem, gpointer user_data)
580 fs = gtk_file_selection_new(_("Save file as..."));
581 g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs)->ok_button),
583 G_CALLBACK(store_filename), (gpointer) fs);
584 g_signal_connect_swapped(GTK_OBJECT
585 (GTK_FILE_SELECTION(fs)->ok_button),
586 "clicked", G_CALLBACK(gtk_widget_destroy),
588 g_signal_connect_swapped(GTK_OBJECT
589 (GTK_FILE_SELECTION(fs)->cancel_button),
590 "clicked", G_CALLBACK(gtk_widget_destroy),
596 void on_quit1_activate(GtkMenuItem * menuitem, gpointer user_data)
598 if (!on_window1_delete_event(NULL, NULL, NULL))
599 gtk_widget_destroy(GTK_WIDGET(main_wnd));
603 void on_show_name1_activate(GtkMenuItem * menuitem, gpointer user_data)
605 GtkTreeViewColumn *col;
607 show_name = GTK_CHECK_MENU_ITEM(menuitem)->active;
608 col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_NAME);
610 gtk_tree_view_column_set_visible(col, show_name);
614 void on_show_range1_activate(GtkMenuItem * menuitem, gpointer user_data)
616 GtkTreeViewColumn *col;
618 show_range = GTK_CHECK_MENU_ITEM(menuitem)->active;
619 col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_NO);
621 gtk_tree_view_column_set_visible(col, show_range);
622 col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_MOD);
624 gtk_tree_view_column_set_visible(col, show_range);
625 col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_YES);
627 gtk_tree_view_column_set_visible(col, show_range);
632 void on_show_data1_activate(GtkMenuItem * menuitem, gpointer user_data)
634 GtkTreeViewColumn *col;
636 show_value = GTK_CHECK_MENU_ITEM(menuitem)->active;
637 col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_VALUE);
639 gtk_tree_view_column_set_visible(col, show_value);
644 on_set_option_mode1_activate(GtkMenuItem *menuitem, gpointer user_data)
646 opt_mode = OPT_NORMAL;
647 gtk_tree_store_clear(tree2);
648 display_tree(&rootmenu); /* instead of update_tree to speed-up */
653 on_set_option_mode2_activate(GtkMenuItem *menuitem, gpointer user_data)
656 gtk_tree_store_clear(tree2);
657 display_tree(&rootmenu); /* instead of update_tree to speed-up */
662 on_set_option_mode3_activate(GtkMenuItem *menuitem, gpointer user_data)
664 opt_mode = OPT_PROMPT;
665 gtk_tree_store_clear(tree2);
666 display_tree(&rootmenu); /* instead of update_tree to speed-up */
670 void on_introduction1_activate(GtkMenuItem * menuitem, gpointer user_data)
673 const gchar *intro_text = _(
674 "Welcome to gkc, the GTK+ graphical configuration tool\n"
675 "For each option, a blank box indicates the feature is disabled, a\n"
676 "check indicates it is enabled, and a dot indicates that it is to\n"
677 "be compiled as a module. Clicking on the box will cycle through the three states.\n"
679 "If you do not see an option (e.g., a device driver) that you\n"
680 "believe should be present, try turning on Show All Options\n"
681 "under the Options menu.\n"
682 "Although there is no cross reference yet to help you figure out\n"
683 "what other options must be enabled to support the option you\n"
684 "are interested in, you can still view the help of a grayed-out\n"
687 "Toggling Show Debug Info under the Options menu will show \n"
688 "the dependencies, which you can then match by examining other options.");
690 dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
691 GTK_DIALOG_DESTROY_WITH_PARENT,
693 GTK_BUTTONS_CLOSE, intro_text);
694 g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
695 G_CALLBACK(gtk_widget_destroy),
697 gtk_widget_show_all(dialog);
701 void on_about1_activate(GtkMenuItem * menuitem, gpointer user_data)
704 const gchar *about_text =
705 _("gkc is copyright (c) 2002 Romain Lievin <roms@lpg.ticalc.org>.\n"
706 "Based on the source code from Roman Zippel.\n");
708 dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
709 GTK_DIALOG_DESTROY_WITH_PARENT,
711 GTK_BUTTONS_CLOSE, about_text);
712 g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
713 G_CALLBACK(gtk_widget_destroy),
715 gtk_widget_show_all(dialog);
719 void on_license1_activate(GtkMenuItem * menuitem, gpointer user_data)
722 const gchar *license_text =
723 _("gkc is released under the terms of the GNU GPL v2.\n"
724 "For more information, please see the source code or\n"
725 "visit http://www.fsf.org/licenses/licenses.html\n");
727 dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
728 GTK_DIALOG_DESTROY_WITH_PARENT,
730 GTK_BUTTONS_CLOSE, license_text);
731 g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
732 G_CALLBACK(gtk_widget_destroy),
734 gtk_widget_show_all(dialog);
738 void on_back_clicked(GtkButton * button, gpointer user_data)
740 enum prop_type ptype;
742 current = current->parent;
743 ptype = current->prompt ? current->prompt->type : P_UNKNOWN;
745 current = current->parent;
748 if (current == &rootmenu)
749 gtk_widget_set_sensitive(back_btn, FALSE);
753 void on_load_clicked(GtkButton * button, gpointer user_data)
755 on_load1_activate(NULL, user_data);
759 void on_single_clicked(GtkButton * button, gpointer user_data)
761 view_mode = SINGLE_VIEW;
762 gtk_paned_set_position(GTK_PANED(hpaned), 0);
763 gtk_widget_hide(tree1_w);
769 void on_split_clicked(GtkButton * button, gpointer user_data)
772 view_mode = SPLIT_VIEW;
773 gtk_widget_show(tree1_w);
774 gtk_window_get_default_size(GTK_WINDOW(main_wnd), &w, &h);
775 gtk_paned_set_position(GTK_PANED(hpaned), w / 2);
777 gtk_tree_store_clear(tree2);
780 /* Disable back btn, like in full mode. */
781 gtk_widget_set_sensitive(back_btn, FALSE);
785 void on_full_clicked(GtkButton * button, gpointer user_data)
787 view_mode = FULL_VIEW;
788 gtk_paned_set_position(GTK_PANED(hpaned), 0);
789 gtk_widget_hide(tree1_w);
791 gtk_tree_store_clear(tree2);
792 display_tree(&rootmenu);
793 gtk_widget_set_sensitive(back_btn, FALSE);
797 void on_collapse_clicked(GtkButton * button, gpointer user_data)
799 gtk_tree_view_collapse_all(GTK_TREE_VIEW(tree2_w));
803 void on_expand_clicked(GtkButton * button, gpointer user_data)
805 gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w));
809 /* CTree Callbacks */
811 /* Change hex/int/string value in the cell */
812 static void renderer_edited(GtkCellRendererText * cell,
813 const gchar * path_string,
814 const gchar * new_text, gpointer user_data)
816 GtkTreePath *path = gtk_tree_path_new_from_string(path_string);
818 const char *old_def, *new_def;
822 if (!gtk_tree_model_get_iter(model2, &iter, path))
825 gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
828 gtk_tree_model_get(model2, &iter, COL_VALUE, &old_def, -1);
831 sym_set_string_value(sym, new_def);
833 update_tree(&rootmenu, NULL);
835 gtk_tree_path_free(path);
838 /* Change the value of a symbol and update the tree */
839 static void change_sym_value(struct menu *menu, gint col)
841 struct symbol *sym = menu->sym;
842 tristate oldval, newval;
849 else if (col == COL_MOD)
851 else if (col == COL_YES)
856 switch (sym_get_type(sym)) {
859 oldval = sym_get_tristate_value(sym);
860 if (!sym_tristate_within_range(sym, newval))
862 sym_set_tristate_value(sym, newval);
863 if (view_mode == FULL_VIEW)
864 update_tree(&rootmenu, NULL);
865 else if (view_mode == SPLIT_VIEW) {
866 update_tree(browsed, NULL);
869 else if (view_mode == SINGLE_VIEW)
870 display_tree_part(); //fixme: keep exp/coll
880 static void toggle_sym_value(struct menu *menu)
885 sym_toggle_tristate_value(menu->sym);
886 if (view_mode == FULL_VIEW)
887 update_tree(&rootmenu, NULL);
888 else if (view_mode == SPLIT_VIEW) {
889 update_tree(browsed, NULL);
892 else if (view_mode == SINGLE_VIEW)
893 display_tree_part(); //fixme: keep exp/coll
896 static void renderer_toggled(GtkCellRendererToggle * cell,
897 gchar * path_string, gpointer user_data)
899 GtkTreePath *path, *sel_path = NULL;
900 GtkTreeIter iter, sel_iter;
901 GtkTreeSelection *sel;
904 path = gtk_tree_path_new_from_string(path_string);
905 if (!gtk_tree_model_get_iter(model2, &iter, path))
908 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree2_w));
909 if (gtk_tree_selection_get_selected(sel, NULL, &sel_iter))
910 sel_path = gtk_tree_model_get_path(model2, &sel_iter);
913 if (gtk_tree_path_compare(path, sel_path))
916 gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
917 toggle_sym_value(menu);
920 gtk_tree_path_free(sel_path);
922 gtk_tree_path_free(path);
925 static gint column2index(GtkTreeViewColumn * column)
929 for (i = 0; i < COL_NUMBER; i++) {
930 GtkTreeViewColumn *col;
932 col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), i);
941 /* User click: update choice (full) or goes down (single) */
943 on_treeview2_button_press_event(GtkWidget * widget,
944 GdkEventButton * event, gpointer user_data)
946 GtkTreeView *view = GTK_TREE_VIEW(widget);
948 GtkTreeViewColumn *column;
953 #if GTK_CHECK_VERSION(2,1,4) // bug in ctree with earlier version of GTK
954 gint tx = (gint) event->x;
955 gint ty = (gint) event->y;
958 gtk_tree_view_get_path_at_pos(view, tx, ty, &path, &column, &cx,
961 gtk_tree_view_get_cursor(view, &path, &column);
966 if (!gtk_tree_model_get_iter(model2, &iter, path))
968 gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
970 col = column2index(column);
971 if (event->type == GDK_2BUTTON_PRESS) {
972 enum prop_type ptype;
973 ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
975 if (ptype == P_MENU && view_mode != FULL_VIEW && col == COL_OPTION) {
976 // goes down into menu
979 gtk_widget_set_sensitive(back_btn, TRUE);
980 } else if ((col == COL_OPTION)) {
981 toggle_sym_value(menu);
982 gtk_tree_view_expand_row(view, path, TRUE);
985 if (col == COL_VALUE) {
986 toggle_sym_value(menu);
987 gtk_tree_view_expand_row(view, path, TRUE);
988 } else if (col == COL_NO || col == COL_MOD
990 change_sym_value(menu, col);
991 gtk_tree_view_expand_row(view, path, TRUE);
998 /* Key pressed: update choice */
1000 on_treeview2_key_press_event(GtkWidget * widget,
1001 GdkEventKey * event, gpointer user_data)
1003 GtkTreeView *view = GTK_TREE_VIEW(widget);
1005 GtkTreeViewColumn *column;
1010 gtk_tree_view_get_cursor(view, &path, &column);
1014 if (event->keyval == GDK_space) {
1015 if (gtk_tree_view_row_expanded(view, path))
1016 gtk_tree_view_collapse_row(view, path);
1018 gtk_tree_view_expand_row(view, path, FALSE);
1021 if (event->keyval == GDK_KP_Enter) {
1023 if (widget == tree1_w)
1026 gtk_tree_model_get_iter(model2, &iter, path);
1027 gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
1029 if (!strcasecmp(event->string, "n"))
1031 else if (!strcasecmp(event->string, "m"))
1033 else if (!strcasecmp(event->string, "y"))
1037 change_sym_value(menu, col);
1043 /* Row selection changed: update help */
1045 on_treeview2_cursor_changed(GtkTreeView * treeview, gpointer user_data)
1047 GtkTreeSelection *selection;
1051 selection = gtk_tree_view_get_selection(treeview);
1052 if (gtk_tree_selection_get_selected(selection, &model2, &iter)) {
1053 gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
1054 text_insert_help(menu);
1059 /* User click: display sub-tree in the right frame. */
1061 on_treeview1_button_press_event(GtkWidget * widget,
1062 GdkEventButton * event, gpointer user_data)
1064 GtkTreeView *view = GTK_TREE_VIEW(widget);
1066 GtkTreeViewColumn *column;
1070 gint tx = (gint) event->x;
1071 gint ty = (gint) event->y;
1074 gtk_tree_view_get_path_at_pos(view, tx, ty, &path, &column, &cx,
1079 gtk_tree_model_get_iter(model1, &iter, path);
1080 gtk_tree_model_get(model1, &iter, COL_MENU, &menu, -1);
1082 if (event->type == GDK_2BUTTON_PRESS) {
1083 toggle_sym_value(menu);
1085 display_tree_part();
1088 display_tree_part();
1091 gtk_widget_realize(tree2_w);
1092 gtk_tree_view_set_cursor(view, path, NULL, FALSE);
1093 gtk_widget_grab_focus(tree2_w);
1099 /* Fill a row of strings */
1100 static gchar **fill_row(struct menu *menu)
1102 static gchar *row[COL_NUMBER];
1103 struct symbol *sym = menu->sym;
1107 enum prop_type ptype;
1110 for (i = COL_OPTION; i <= COL_COLOR; i++)
1112 bzero(row, sizeof(row));
1115 g_strdup_printf("%s %s", _(menu_get_prompt(menu)),
1116 sym && !sym_has_value(sym) ? "(NEW)" : "");
1118 if (opt_mode == OPT_ALL && !menu_is_visible(menu))
1119 row[COL_COLOR] = g_strdup("DarkGray");
1120 else if (opt_mode == OPT_PROMPT &&
1121 menu_has_prompt(menu) && !menu_is_visible(menu))
1122 row[COL_COLOR] = g_strdup("DarkGray");
1124 row[COL_COLOR] = g_strdup("Black");
1126 ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
1129 row[COL_PIXBUF] = (gchar *) xpm_menu;
1130 if (view_mode == SINGLE_VIEW)
1131 row[COL_PIXVIS] = GINT_TO_POINTER(TRUE);
1132 row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
1135 row[COL_PIXBUF] = (gchar *) xpm_void;
1136 row[COL_PIXVIS] = GINT_TO_POINTER(FALSE);
1137 row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
1140 row[COL_PIXBUF] = (gchar *) xpm_void;
1141 row[COL_PIXVIS] = GINT_TO_POINTER(FALSE);
1142 row[COL_BTNVIS] = GINT_TO_POINTER(TRUE);
1148 row[COL_NAME] = g_strdup(sym->name);
1150 sym_calc_value(sym);
1151 sym->flags &= ~SYMBOL_CHANGED;
1153 if (sym_is_choice(sym)) { // parse childs for getting final value
1155 struct symbol *def_sym = sym_get_choice_value(sym);
1156 struct menu *def_menu = NULL;
1158 row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
1160 for (child = menu->list; child; child = child->next) {
1161 if (menu_is_visible(child)
1162 && child->sym == def_sym)
1168 g_strdup(_(menu_get_prompt(def_menu)));
1170 if (sym->flags & SYMBOL_CHOICEVAL)
1171 row[COL_BTNRAD] = GINT_TO_POINTER(TRUE);
1173 stype = sym_get_type(sym);
1176 if (GPOINTER_TO_INT(row[COL_PIXVIS]) == FALSE)
1177 row[COL_BTNVIS] = GINT_TO_POINTER(TRUE);
1178 if (sym_is_choice(sym))
1181 val = sym_get_tristate_value(sym);
1184 row[COL_NO] = g_strdup("N");
1185 row[COL_VALUE] = g_strdup("N");
1186 row[COL_BTNACT] = GINT_TO_POINTER(FALSE);
1187 row[COL_BTNINC] = GINT_TO_POINTER(FALSE);
1190 row[COL_MOD] = g_strdup("M");
1191 row[COL_VALUE] = g_strdup("M");
1192 row[COL_BTNINC] = GINT_TO_POINTER(TRUE);
1195 row[COL_YES] = g_strdup("Y");
1196 row[COL_VALUE] = g_strdup("Y");
1197 row[COL_BTNACT] = GINT_TO_POINTER(TRUE);
1198 row[COL_BTNINC] = GINT_TO_POINTER(FALSE);
1202 if (val != no && sym_tristate_within_range(sym, no))
1203 row[COL_NO] = g_strdup("_");
1204 if (val != mod && sym_tristate_within_range(sym, mod))
1205 row[COL_MOD] = g_strdup("_");
1206 if (val != yes && sym_tristate_within_range(sym, yes))
1207 row[COL_YES] = g_strdup("_");
1212 def = sym_get_string_value(sym);
1213 row[COL_VALUE] = g_strdup(def);
1214 row[COL_EDIT] = GINT_TO_POINTER(TRUE);
1215 row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
1223 /* Set the node content with a row of strings */
1224 static void set_node(GtkTreeIter * node, struct menu *menu, gchar ** row)
1230 pix = gdk_pixbuf_new_from_xpm_data((const char **)
1233 gdk_color_parse(row[COL_COLOR], &color);
1234 gdk_colormap_alloc_colors(gdk_colormap_get_system(), &color, 1,
1235 FALSE, FALSE, &success);
1237 gtk_tree_store_set(tree, node,
1238 COL_OPTION, row[COL_OPTION],
1239 COL_NAME, row[COL_NAME],
1240 COL_NO, row[COL_NO],
1241 COL_MOD, row[COL_MOD],
1242 COL_YES, row[COL_YES],
1243 COL_VALUE, row[COL_VALUE],
1244 COL_MENU, (gpointer) menu,
1246 COL_EDIT, GPOINTER_TO_INT(row[COL_EDIT]),
1248 COL_PIXVIS, GPOINTER_TO_INT(row[COL_PIXVIS]),
1249 COL_BTNVIS, GPOINTER_TO_INT(row[COL_BTNVIS]),
1250 COL_BTNACT, GPOINTER_TO_INT(row[COL_BTNACT]),
1251 COL_BTNINC, GPOINTER_TO_INT(row[COL_BTNINC]),
1252 COL_BTNRAD, GPOINTER_TO_INT(row[COL_BTNRAD]),
1255 g_object_unref(pix);
1259 /* Add a node to the tree */
1260 static void place_node(struct menu *menu, char **row)
1262 GtkTreeIter *parent = parents[indent - 1];
1263 GtkTreeIter *node = parents[indent];
1265 gtk_tree_store_append(tree, node, parent);
1266 set_node(node, menu, row);
1270 /* Find a node in the GTK+ tree */
1271 static GtkTreeIter found;
1274 * Find a menu in the GtkTree starting at parent.
1276 GtkTreeIter *gtktree_iter_find_node(GtkTreeIter * parent,
1277 struct menu *tofind)
1280 GtkTreeIter *child = &iter;
1284 valid = gtk_tree_model_iter_children(model2, child, parent);
1288 gtk_tree_model_get(model2, child, 6, &menu, -1);
1290 if (menu == tofind) {
1291 memcpy(&found, child, sizeof(GtkTreeIter));
1295 ret = gtktree_iter_find_node(child, tofind);
1299 valid = gtk_tree_model_iter_next(model2, child);
1307 * Update the tree by adding/removing entries
1308 * Does not change other nodes
1310 static void update_tree(struct menu *src, GtkTreeIter * dst)
1312 struct menu *child1;
1313 GtkTreeIter iter, tmp;
1314 GtkTreeIter *child2 = &iter;
1316 GtkTreeIter *sibling;
1318 struct property *prop;
1319 struct menu *menu1, *menu2;
1321 if (src == &rootmenu)
1324 valid = gtk_tree_model_iter_children(model2, child2, dst);
1325 for (child1 = src->list; child1; child1 = child1->next) {
1327 prop = child1->prompt;
1333 gtk_tree_model_get(model2, child2, COL_MENU,
1336 menu2 = NULL; // force adding of a first child
1339 printf("%*c%s | %s\n", indent, ' ',
1340 menu1 ? menu_get_prompt(menu1) : "nil",
1341 menu2 ? menu_get_prompt(menu2) : "nil");
1344 if ((opt_mode == OPT_NORMAL && !menu_is_visible(child1)) ||
1345 (opt_mode == OPT_PROMPT && !menu_has_prompt(child1)) ||
1346 (opt_mode == OPT_ALL && !menu_get_prompt(child1))) {
1349 if (gtktree_iter_find_node(dst, menu1) != NULL) {
1350 memcpy(&tmp, child2, sizeof(GtkTreeIter));
1351 valid = gtk_tree_model_iter_next(model2,
1353 gtk_tree_store_remove(tree2, &tmp);
1355 return; /* next parent */
1357 goto reparse; /* next child */
1362 if (menu1 != menu2) {
1363 if (gtktree_iter_find_node(dst, menu1) == NULL) { // add node
1364 if (!valid && !menu2)
1368 gtk_tree_store_insert_before(tree2,
1371 set_node(child2, menu1, fill_row(menu1));
1374 } else { // remove node
1375 memcpy(&tmp, child2, sizeof(GtkTreeIter));
1376 valid = gtk_tree_model_iter_next(model2,
1378 gtk_tree_store_remove(tree2, &tmp);
1380 return; // next parent
1382 goto reparse; // next child
1384 } else if (sym && (sym->flags & SYMBOL_CHANGED)) {
1385 set_node(child2, menu1, fill_row(menu1));
1389 update_tree(child1, child2);
1392 valid = gtk_tree_model_iter_next(model2, child2);
1397 /* Display the whole tree (single/split/full view) */
1398 static void display_tree(struct menu *menu)
1401 struct property *prop;
1403 enum prop_type ptype;
1405 if (menu == &rootmenu) {
1407 current = &rootmenu;
1410 for (child = menu->list; child; child = child->next) {
1411 prop = child->prompt;
1413 ptype = prop ? prop->type : P_UNKNOWN;
1416 sym->flags &= ~SYMBOL_CHANGED;
1418 if ((view_mode == SPLIT_VIEW)
1419 && !(child->flags & MENU_ROOT) && (tree == tree1))
1422 if ((view_mode == SPLIT_VIEW) && (child->flags & MENU_ROOT)
1426 if ((opt_mode == OPT_NORMAL && menu_is_visible(child)) ||
1427 (opt_mode == OPT_PROMPT && menu_has_prompt(child)) ||
1428 (opt_mode == OPT_ALL && menu_get_prompt(child)))
1429 place_node(child, fill_row(child));
1431 printf("%*c%s: ", indent, ' ', menu_get_prompt(child));
1432 printf("%s", child->flags & MENU_ROOT ? "rootmenu | " : "");
1433 printf("%s", prop_get_type_name(ptype));
1436 printf("%s", sym_type_name(sym->type));
1438 printf("%s", dbg_sym_flags(sym->flags));
1443 if ((view_mode != FULL_VIEW) && (ptype == P_MENU)
1447 if (((menu != &rootmenu) && !(menu->flags & MENU_ROOT))
1448 || (view_mode == FULL_VIEW)
1449 || (view_mode == SPLIT_VIEW))*/
1450 if (((view_mode == SINGLE_VIEW) && (menu->flags & MENU_ROOT))
1451 || (view_mode == FULL_VIEW)
1452 || (view_mode == SPLIT_VIEW)) {
1454 display_tree(child);
1460 /* Display a part of the tree starting at current node (single/split view) */
1461 static void display_tree_part(void)
1464 gtk_tree_store_clear(tree2);
1465 if (view_mode == SINGLE_VIEW)
1466 display_tree(current);
1467 else if (view_mode == SPLIT_VIEW)
1468 display_tree(browsed);
1469 gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w));
1472 /* Display the list in the left frame (split view) */
1473 static void display_list(void)
1476 gtk_tree_store_clear(tree1);
1479 display_tree(&rootmenu);
1480 gtk_tree_view_expand_all(GTK_TREE_VIEW(tree1_w));
1484 void fixup_rootmenu(struct menu *menu)
1487 static int menu_cnt = 0;
1489 menu->flags |= MENU_ROOT;
1490 for (child = menu->list; child; child = child->next) {
1491 if (child->prompt && child->prompt->type == P_MENU) {
1493 fixup_rootmenu(child);
1495 } else if (!menu_cnt)
1496 fixup_rootmenu(child);
1502 int main(int ac, char *av[])
1508 #ifndef LKC_DIRECT_LINK
1512 bindtextdomain(PACKAGE, LOCALEDIR);
1513 bind_textdomain_codeset(PACKAGE, "UTF-8");
1514 textdomain(PACKAGE);
1521 //add_pixmap_directory (PACKAGE_DATA_DIR "/" PACKAGE "/pixmaps");
1522 //add_pixmap_directory (PACKAGE_SOURCE_DIR "/pixmaps");
1524 /* Determine GUI path */
1525 env = getenv(SRCTREE);
1527 glade_file = g_strconcat(env, "/scripts/kconfig/gconf.glade", NULL);
1528 else if (av[0][0] == '/')
1529 glade_file = g_strconcat(av[0], ".glade", NULL);
1531 glade_file = g_strconcat(g_get_current_dir(), "/", av[0], ".glade", NULL);
1533 /* Load the interface and connect signals */
1534 init_main_window(glade_file);
1540 if (ac > 1 && av[1][0] == '-') {
1547 printf("%s <config>\n", av[0]);
1555 fixup_rootmenu(&rootmenu);
1558 switch (view_mode) {
1560 display_tree_part();
1566 display_tree(&rootmenu);
1575 static void conf_changed(void)
1577 bool changed = conf_get_changed();
1578 gtk_widget_set_sensitive(save_btn, changed);
1579 gtk_widget_set_sensitive(save_menu_item, changed);