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.
17 #include <glade/glade.h>
20 #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_NO_WRITE)
105 strcat(buf, "no_write/");
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;
138 xml = glade_xml_new(glade_file, "window1", NULL);
140 g_error("GUI loading failed !\n");
141 glade_xml_signal_autoconnect(xml);
143 main_wnd = glade_xml_get_widget(xml, "window1");
144 hpaned = glade_xml_get_widget(xml, "hpaned1");
145 vpaned = glade_xml_get_widget(xml, "vpaned1");
146 tree1_w = glade_xml_get_widget(xml, "treeview1");
147 tree2_w = glade_xml_get_widget(xml, "treeview2");
148 text_w = glade_xml_get_widget(xml, "textview3");
150 back_btn = glade_xml_get_widget(xml, "button1");
151 gtk_widget_set_sensitive(back_btn, FALSE);
153 widget = glade_xml_get_widget(xml, "show_name1");
154 gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget,
157 widget = glade_xml_get_widget(xml, "show_range1");
158 gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget,
161 widget = glade_xml_get_widget(xml, "show_data1");
162 gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget,
165 save_btn = glade_xml_get_widget(xml, "button3");
166 save_menu_item = glade_xml_get_widget(xml, "save1");
167 conf_set_changed_callback(conf_changed);
169 style = gtk_widget_get_style(main_wnd);
170 widget = glade_xml_get_widget(xml, "toolbar1");
172 replace_button_icon(xml, main_wnd->window, style,
173 "button4", (gchar **) xpm_single_view);
174 replace_button_icon(xml, main_wnd->window, style,
175 "button5", (gchar **) xpm_split_view);
176 replace_button_icon(xml, main_wnd->window, style,
177 "button6", (gchar **) xpm_tree_view);
179 txtbuf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w));
180 tag1 = gtk_text_buffer_create_tag(txtbuf, "mytag1",
182 "weight", PANGO_WEIGHT_BOLD,
184 tag2 = gtk_text_buffer_create_tag(txtbuf, "mytag2",
185 /*"style", PANGO_STYLE_OBLIQUE, */
188 gtk_window_set_title(GTK_WINDOW(main_wnd), rootmenu.prompt->text);
190 gtk_widget_show(main_wnd);
193 void init_tree_model(void)
197 tree = tree2 = gtk_tree_store_new(COL_NUMBER,
198 G_TYPE_STRING, G_TYPE_STRING,
199 G_TYPE_STRING, G_TYPE_STRING,
200 G_TYPE_STRING, G_TYPE_STRING,
201 G_TYPE_POINTER, GDK_TYPE_COLOR,
202 G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF,
203 G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
204 G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
206 model2 = GTK_TREE_MODEL(tree2);
208 for (parents[0] = NULL, i = 1; i < 256; i++)
209 parents[i] = (GtkTreeIter *) g_malloc(sizeof(GtkTreeIter));
211 tree1 = gtk_tree_store_new(COL_NUMBER,
212 G_TYPE_STRING, G_TYPE_STRING,
213 G_TYPE_STRING, G_TYPE_STRING,
214 G_TYPE_STRING, G_TYPE_STRING,
215 G_TYPE_POINTER, GDK_TYPE_COLOR,
216 G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF,
217 G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
218 G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
220 model1 = GTK_TREE_MODEL(tree1);
223 void init_left_tree(void)
225 GtkTreeView *view = GTK_TREE_VIEW(tree1_w);
226 GtkCellRenderer *renderer;
227 GtkTreeSelection *sel;
228 GtkTreeViewColumn *column;
230 gtk_tree_view_set_model(view, model1);
231 gtk_tree_view_set_headers_visible(view, TRUE);
232 gtk_tree_view_set_rules_hint(view, TRUE);
234 column = gtk_tree_view_column_new();
235 gtk_tree_view_append_column(view, column);
236 gtk_tree_view_column_set_title(column, "Options");
238 renderer = gtk_cell_renderer_toggle_new();
239 gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
241 gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
243 "active", COL_BTNACT,
244 "inconsistent", COL_BTNINC,
245 "visible", COL_BTNVIS,
246 "radio", COL_BTNRAD, NULL);
247 renderer = gtk_cell_renderer_text_new();
248 gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
250 gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
256 sel = gtk_tree_view_get_selection(view);
257 gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
258 gtk_widget_realize(tree1_w);
261 static void renderer_edited(GtkCellRendererText * cell,
262 const gchar * path_string,
263 const gchar * new_text, gpointer user_data);
265 void init_right_tree(void)
267 GtkTreeView *view = GTK_TREE_VIEW(tree2_w);
268 GtkCellRenderer *renderer;
269 GtkTreeSelection *sel;
270 GtkTreeViewColumn *column;
273 gtk_tree_view_set_model(view, model2);
274 gtk_tree_view_set_headers_visible(view, TRUE);
275 gtk_tree_view_set_rules_hint(view, TRUE);
277 column = gtk_tree_view_column_new();
278 gtk_tree_view_append_column(view, column);
279 gtk_tree_view_column_set_title(column, "Options");
281 renderer = gtk_cell_renderer_pixbuf_new();
282 gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
284 gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
286 "pixbuf", COL_PIXBUF,
287 "visible", COL_PIXVIS, NULL);
288 renderer = gtk_cell_renderer_toggle_new();
289 gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
291 gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
293 "active", COL_BTNACT,
294 "inconsistent", COL_BTNINC,
295 "visible", COL_BTNVIS,
296 "radio", COL_BTNRAD, NULL);
297 renderer = gtk_cell_renderer_text_new();
298 gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
300 gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
306 renderer = gtk_cell_renderer_text_new();
307 gtk_tree_view_insert_column_with_attributes(view, -1,
312 renderer = gtk_cell_renderer_text_new();
313 gtk_tree_view_insert_column_with_attributes(view, -1,
318 renderer = gtk_cell_renderer_text_new();
319 gtk_tree_view_insert_column_with_attributes(view, -1,
324 renderer = gtk_cell_renderer_text_new();
325 gtk_tree_view_insert_column_with_attributes(view, -1,
330 renderer = gtk_cell_renderer_text_new();
331 gtk_tree_view_insert_column_with_attributes(view, -1,
338 g_signal_connect(G_OBJECT(renderer), "edited",
339 G_CALLBACK(renderer_edited), NULL);
341 column = gtk_tree_view_get_column(view, COL_NAME);
342 gtk_tree_view_column_set_visible(column, show_name);
343 column = gtk_tree_view_get_column(view, COL_NO);
344 gtk_tree_view_column_set_visible(column, show_range);
345 column = gtk_tree_view_get_column(view, COL_MOD);
346 gtk_tree_view_column_set_visible(column, show_range);
347 column = gtk_tree_view_get_column(view, COL_YES);
348 gtk_tree_view_column_set_visible(column, show_range);
349 column = gtk_tree_view_get_column(view, COL_VALUE);
350 gtk_tree_view_column_set_visible(column, show_value);
353 for (i = 0; i < COL_VALUE; i++) {
354 column = gtk_tree_view_get_column(view, i);
355 gtk_tree_view_column_set_resizable(column, TRUE);
359 sel = gtk_tree_view_get_selection(view);
360 gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
364 /* Utility Functions */
367 static void text_insert_help(struct menu *menu)
369 GtkTextBuffer *buffer;
370 GtkTextIter start, end;
371 const char *prompt = menu_get_prompt(menu);
372 struct gstr help = str_new();
374 menu_get_ext_help(menu, &help);
376 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w));
377 gtk_text_buffer_get_bounds(buffer, &start, &end);
378 gtk_text_buffer_delete(buffer, &start, &end);
379 gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_w), 15);
381 gtk_text_buffer_get_end_iter(buffer, &end);
382 gtk_text_buffer_insert_with_tags(buffer, &end, prompt, -1, tag1,
384 gtk_text_buffer_insert_at_cursor(buffer, "\n\n", 2);
385 gtk_text_buffer_get_end_iter(buffer, &end);
386 gtk_text_buffer_insert_with_tags(buffer, &end, str_get(&help), -1, tag2,
392 static void text_insert_msg(const char *title, const char *message)
394 GtkTextBuffer *buffer;
395 GtkTextIter start, end;
396 const char *msg = message;
398 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w));
399 gtk_text_buffer_get_bounds(buffer, &start, &end);
400 gtk_text_buffer_delete(buffer, &start, &end);
401 gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_w), 15);
403 gtk_text_buffer_get_end_iter(buffer, &end);
404 gtk_text_buffer_insert_with_tags(buffer, &end, title, -1, tag1,
406 gtk_text_buffer_insert_at_cursor(buffer, "\n\n", 2);
407 gtk_text_buffer_get_end_iter(buffer, &end);
408 gtk_text_buffer_insert_with_tags(buffer, &end, msg, -1, tag2,
413 /* Main Windows Callbacks */
415 void on_save_activate(GtkMenuItem * menuitem, gpointer user_data);
416 gboolean on_window1_delete_event(GtkWidget * widget, GdkEvent * event,
419 GtkWidget *dialog, *label;
422 if (!conf_get_changed())
425 dialog = gtk_dialog_new_with_buttons("Warning !",
426 GTK_WINDOW(main_wnd),
429 GTK_DIALOG_DESTROY_WITH_PARENT),
435 GTK_RESPONSE_CANCEL, NULL);
436 gtk_dialog_set_default_response(GTK_DIALOG(dialog),
437 GTK_RESPONSE_CANCEL);
439 label = gtk_label_new("\nSave configuration ?\n");
440 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), label);
441 gtk_widget_show(label);
443 result = gtk_dialog_run(GTK_DIALOG(dialog));
445 case GTK_RESPONSE_YES:
446 on_save_activate(NULL, NULL);
448 case GTK_RESPONSE_NO:
450 case GTK_RESPONSE_CANCEL:
451 case GTK_RESPONSE_DELETE_EVENT:
453 gtk_widget_destroy(dialog);
461 void on_window1_destroy(GtkObject * object, gpointer user_data)
468 on_window1_size_request(GtkWidget * widget,
469 GtkRequisition * requisition, gpointer user_data)
474 if (widget->window == NULL)
475 gtk_window_get_default_size(GTK_WINDOW(main_wnd), &w, &h);
477 gdk_window_get_size(widget->window, &w, &h);
483 gtk_paned_set_position(GTK_PANED(vpaned), 2 * h / 3);
487 /* Menu & Toolbar Callbacks */
491 load_filename(GtkFileSelection * file_selector, gpointer user_data)
495 fn = gtk_file_selection_get_filename(GTK_FILE_SELECTION
499 text_insert_msg("Error", "Unable to load configuration !");
501 display_tree(&rootmenu);
504 void on_load1_activate(GtkMenuItem * menuitem, gpointer user_data)
508 fs = gtk_file_selection_new("Load file...");
509 g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs)->ok_button),
511 G_CALLBACK(load_filename), (gpointer) fs);
512 g_signal_connect_swapped(GTK_OBJECT
513 (GTK_FILE_SELECTION(fs)->ok_button),
514 "clicked", G_CALLBACK(gtk_widget_destroy),
516 g_signal_connect_swapped(GTK_OBJECT
517 (GTK_FILE_SELECTION(fs)->cancel_button),
518 "clicked", G_CALLBACK(gtk_widget_destroy),
524 void on_save_activate(GtkMenuItem * menuitem, gpointer user_data)
526 if (conf_write(NULL))
527 text_insert_msg("Error", "Unable to save configuration !");
528 conf_write_autoconf(0);
533 store_filename(GtkFileSelection * file_selector, gpointer user_data)
537 fn = gtk_file_selection_get_filename(GTK_FILE_SELECTION
541 text_insert_msg("Error", "Unable to save configuration !");
543 gtk_widget_destroy(GTK_WIDGET(user_data));
546 void on_save_as1_activate(GtkMenuItem * menuitem, gpointer user_data)
550 fs = gtk_file_selection_new("Save file as...");
551 g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs)->ok_button),
553 G_CALLBACK(store_filename), (gpointer) fs);
554 g_signal_connect_swapped(GTK_OBJECT
555 (GTK_FILE_SELECTION(fs)->ok_button),
556 "clicked", G_CALLBACK(gtk_widget_destroy),
558 g_signal_connect_swapped(GTK_OBJECT
559 (GTK_FILE_SELECTION(fs)->cancel_button),
560 "clicked", G_CALLBACK(gtk_widget_destroy),
566 void on_quit1_activate(GtkMenuItem * menuitem, gpointer user_data)
568 if (!on_window1_delete_event(NULL, NULL, NULL))
569 gtk_widget_destroy(GTK_WIDGET(main_wnd));
573 void on_show_name1_activate(GtkMenuItem * menuitem, gpointer user_data)
575 GtkTreeViewColumn *col;
577 show_name = GTK_CHECK_MENU_ITEM(menuitem)->active;
578 col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_NAME);
580 gtk_tree_view_column_set_visible(col, show_name);
584 void on_show_range1_activate(GtkMenuItem * menuitem, gpointer user_data)
586 GtkTreeViewColumn *col;
588 show_range = GTK_CHECK_MENU_ITEM(menuitem)->active;
589 col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_NO);
591 gtk_tree_view_column_set_visible(col, show_range);
592 col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_MOD);
594 gtk_tree_view_column_set_visible(col, show_range);
595 col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_YES);
597 gtk_tree_view_column_set_visible(col, show_range);
602 void on_show_data1_activate(GtkMenuItem * menuitem, gpointer user_data)
604 GtkTreeViewColumn *col;
606 show_value = GTK_CHECK_MENU_ITEM(menuitem)->active;
607 col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_VALUE);
609 gtk_tree_view_column_set_visible(col, show_value);
614 on_set_option_mode1_activate(GtkMenuItem *menuitem, gpointer user_data)
616 opt_mode = OPT_NORMAL;
617 gtk_tree_store_clear(tree2);
618 display_tree(&rootmenu); /* instead of update_tree to speed-up */
623 on_set_option_mode2_activate(GtkMenuItem *menuitem, gpointer user_data)
626 gtk_tree_store_clear(tree2);
627 display_tree(&rootmenu); /* instead of update_tree to speed-up */
632 on_set_option_mode3_activate(GtkMenuItem *menuitem, gpointer user_data)
634 opt_mode = OPT_PROMPT;
635 gtk_tree_store_clear(tree2);
636 display_tree(&rootmenu); /* instead of update_tree to speed-up */
640 void on_introduction1_activate(GtkMenuItem * menuitem, gpointer user_data)
643 const gchar *intro_text =
644 "Welcome to gkc, the GTK+ graphical configuration tool\n"
645 "For each option, a blank box indicates the feature is disabled, a\n"
646 "check indicates it is enabled, and a dot indicates that it is to\n"
647 "be compiled as a module. Clicking on the box will cycle through the three states.\n"
649 "If you do not see an option (e.g., a device driver) that you\n"
650 "believe should be present, try turning on Show All Options\n"
651 "under the Options menu.\n"
652 "Although there is no cross reference yet to help you figure out\n"
653 "what other options must be enabled to support the option you\n"
654 "are interested in, you can still view the help of a grayed-out\n"
657 "Toggling Show Debug Info under the Options menu will show \n"
658 "the dependencies, which you can then match by examining other options.";
660 dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
661 GTK_DIALOG_DESTROY_WITH_PARENT,
663 GTK_BUTTONS_CLOSE, "%s", intro_text);
664 g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
665 G_CALLBACK(gtk_widget_destroy),
667 gtk_widget_show_all(dialog);
671 void on_about1_activate(GtkMenuItem * menuitem, gpointer user_data)
674 const gchar *about_text =
675 "gkc is copyright (c) 2002 Romain Lievin <roms@lpg.ticalc.org>.\n"
676 "Based on the source code from Roman Zippel.\n";
678 dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
679 GTK_DIALOG_DESTROY_WITH_PARENT,
681 GTK_BUTTONS_CLOSE, "%s", about_text);
682 g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
683 G_CALLBACK(gtk_widget_destroy),
685 gtk_widget_show_all(dialog);
689 void on_license1_activate(GtkMenuItem * menuitem, gpointer user_data)
692 const gchar *license_text =
693 "gkc is released under the terms of the GNU GPL v2.\n"
694 "For more information, please see the source code or\n"
695 "visit http://www.fsf.org/licenses/licenses.html\n";
697 dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
698 GTK_DIALOG_DESTROY_WITH_PARENT,
700 GTK_BUTTONS_CLOSE, "%s", license_text);
701 g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
702 G_CALLBACK(gtk_widget_destroy),
704 gtk_widget_show_all(dialog);
708 void on_back_clicked(GtkButton * button, gpointer user_data)
710 enum prop_type ptype;
712 current = current->parent;
713 ptype = current->prompt ? current->prompt->type : P_UNKNOWN;
715 current = current->parent;
718 if (current == &rootmenu)
719 gtk_widget_set_sensitive(back_btn, FALSE);
723 void on_load_clicked(GtkButton * button, gpointer user_data)
725 on_load1_activate(NULL, user_data);
729 void on_single_clicked(GtkButton * button, gpointer user_data)
731 view_mode = SINGLE_VIEW;
732 gtk_widget_hide(tree1_w);
738 void on_split_clicked(GtkButton * button, gpointer user_data)
741 view_mode = SPLIT_VIEW;
742 gtk_widget_show(tree1_w);
743 gtk_window_get_default_size(GTK_WINDOW(main_wnd), &w, &h);
744 gtk_paned_set_position(GTK_PANED(hpaned), w / 2);
746 gtk_tree_store_clear(tree2);
749 /* Disable back btn, like in full mode. */
750 gtk_widget_set_sensitive(back_btn, FALSE);
754 void on_full_clicked(GtkButton * button, gpointer user_data)
756 view_mode = FULL_VIEW;
757 gtk_widget_hide(tree1_w);
759 gtk_tree_store_clear(tree2);
760 display_tree(&rootmenu);
761 gtk_widget_set_sensitive(back_btn, FALSE);
765 void on_collapse_clicked(GtkButton * button, gpointer user_data)
767 gtk_tree_view_collapse_all(GTK_TREE_VIEW(tree2_w));
771 void on_expand_clicked(GtkButton * button, gpointer user_data)
773 gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w));
777 /* CTree Callbacks */
779 /* Change hex/int/string value in the cell */
780 static void renderer_edited(GtkCellRendererText * cell,
781 const gchar * path_string,
782 const gchar * new_text, gpointer user_data)
784 GtkTreePath *path = gtk_tree_path_new_from_string(path_string);
786 const char *old_def, *new_def;
790 if (!gtk_tree_model_get_iter(model2, &iter, path))
793 gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
796 gtk_tree_model_get(model2, &iter, COL_VALUE, &old_def, -1);
799 sym_set_string_value(sym, new_def);
801 update_tree(&rootmenu, NULL);
803 gtk_tree_path_free(path);
806 /* Change the value of a symbol and update the tree */
807 static void change_sym_value(struct menu *menu, gint col)
809 struct symbol *sym = menu->sym;
817 else if (col == COL_MOD)
819 else if (col == COL_YES)
824 switch (sym_get_type(sym)) {
827 if (!sym_tristate_within_range(sym, newval))
829 sym_set_tristate_value(sym, newval);
830 if (view_mode == FULL_VIEW)
831 update_tree(&rootmenu, NULL);
832 else if (view_mode == SPLIT_VIEW) {
833 update_tree(browsed, NULL);
836 else if (view_mode == SINGLE_VIEW)
837 display_tree_part(); //fixme: keep exp/coll
847 static void toggle_sym_value(struct menu *menu)
852 sym_toggle_tristate_value(menu->sym);
853 if (view_mode == FULL_VIEW)
854 update_tree(&rootmenu, NULL);
855 else if (view_mode == SPLIT_VIEW) {
856 update_tree(browsed, NULL);
859 else if (view_mode == SINGLE_VIEW)
860 display_tree_part(); //fixme: keep exp/coll
863 static gint column2index(GtkTreeViewColumn * column)
867 for (i = 0; i < COL_NUMBER; i++) {
868 GtkTreeViewColumn *col;
870 col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), i);
879 /* User click: update choice (full) or goes down (single) */
881 on_treeview2_button_press_event(GtkWidget * widget,
882 GdkEventButton * event, gpointer user_data)
884 GtkTreeView *view = GTK_TREE_VIEW(widget);
886 GtkTreeViewColumn *column;
891 #if GTK_CHECK_VERSION(2,1,4) // bug in ctree with earlier version of GTK
892 gint tx = (gint) event->x;
893 gint ty = (gint) event->y;
896 gtk_tree_view_get_path_at_pos(view, tx, ty, &path, &column, &cx,
899 gtk_tree_view_get_cursor(view, &path, &column);
904 if (!gtk_tree_model_get_iter(model2, &iter, path))
906 gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
908 col = column2index(column);
909 if (event->type == GDK_2BUTTON_PRESS) {
910 enum prop_type ptype;
911 ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
913 if (ptype == P_MENU && view_mode != FULL_VIEW && col == COL_OPTION) {
914 // goes down into menu
917 gtk_widget_set_sensitive(back_btn, TRUE);
918 } else if (col == COL_OPTION) {
919 toggle_sym_value(menu);
920 gtk_tree_view_expand_row(view, path, TRUE);
923 if (col == COL_VALUE) {
924 toggle_sym_value(menu);
925 gtk_tree_view_expand_row(view, path, TRUE);
926 } else if (col == COL_NO || col == COL_MOD
928 change_sym_value(menu, col);
929 gtk_tree_view_expand_row(view, path, TRUE);
936 /* Key pressed: update choice */
938 on_treeview2_key_press_event(GtkWidget * widget,
939 GdkEventKey * event, gpointer user_data)
941 GtkTreeView *view = GTK_TREE_VIEW(widget);
943 GtkTreeViewColumn *column;
948 gtk_tree_view_get_cursor(view, &path, &column);
952 if (event->keyval == GDK_space) {
953 if (gtk_tree_view_row_expanded(view, path))
954 gtk_tree_view_collapse_row(view, path);
956 gtk_tree_view_expand_row(view, path, FALSE);
959 if (event->keyval == GDK_KP_Enter) {
961 if (widget == tree1_w)
964 gtk_tree_model_get_iter(model2, &iter, path);
965 gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
967 if (!strcasecmp(event->string, "n"))
969 else if (!strcasecmp(event->string, "m"))
971 else if (!strcasecmp(event->string, "y"))
975 change_sym_value(menu, col);
981 /* Row selection changed: update help */
983 on_treeview2_cursor_changed(GtkTreeView * treeview, gpointer user_data)
985 GtkTreeSelection *selection;
989 selection = gtk_tree_view_get_selection(treeview);
990 if (gtk_tree_selection_get_selected(selection, &model2, &iter)) {
991 gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
992 text_insert_help(menu);
997 /* User click: display sub-tree in the right frame. */
999 on_treeview1_button_press_event(GtkWidget * widget,
1000 GdkEventButton * event, gpointer user_data)
1002 GtkTreeView *view = GTK_TREE_VIEW(widget);
1004 GtkTreeViewColumn *column;
1008 gint tx = (gint) event->x;
1009 gint ty = (gint) event->y;
1012 gtk_tree_view_get_path_at_pos(view, tx, ty, &path, &column, &cx,
1017 gtk_tree_model_get_iter(model1, &iter, path);
1018 gtk_tree_model_get(model1, &iter, COL_MENU, &menu, -1);
1020 if (event->type == GDK_2BUTTON_PRESS) {
1021 toggle_sym_value(menu);
1023 display_tree_part();
1026 display_tree_part();
1029 gtk_widget_realize(tree2_w);
1030 gtk_tree_view_set_cursor(view, path, NULL, FALSE);
1031 gtk_widget_grab_focus(tree2_w);
1037 /* Fill a row of strings */
1038 static gchar **fill_row(struct menu *menu)
1040 static gchar *row[COL_NUMBER];
1041 struct symbol *sym = menu->sym;
1045 enum prop_type ptype;
1048 for (i = COL_OPTION; i <= COL_COLOR; i++)
1050 bzero(row, sizeof(row));
1053 g_strdup_printf("%s %s", menu_get_prompt(menu),
1054 sym && !sym_has_value(sym) ? "(NEW)" : "");
1056 if (opt_mode == OPT_ALL && !menu_is_visible(menu))
1057 row[COL_COLOR] = g_strdup("DarkGray");
1058 else if (opt_mode == OPT_PROMPT &&
1059 menu_has_prompt(menu) && !menu_is_visible(menu))
1060 row[COL_COLOR] = g_strdup("DarkGray");
1062 row[COL_COLOR] = g_strdup("Black");
1064 ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
1067 row[COL_PIXBUF] = (gchar *) xpm_menu;
1068 if (view_mode == SINGLE_VIEW)
1069 row[COL_PIXVIS] = GINT_TO_POINTER(TRUE);
1070 row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
1073 row[COL_PIXBUF] = (gchar *) xpm_void;
1074 row[COL_PIXVIS] = GINT_TO_POINTER(FALSE);
1075 row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
1078 row[COL_PIXBUF] = (gchar *) xpm_void;
1079 row[COL_PIXVIS] = GINT_TO_POINTER(FALSE);
1080 row[COL_BTNVIS] = GINT_TO_POINTER(TRUE);
1086 row[COL_NAME] = g_strdup(sym->name);
1088 sym_calc_value(sym);
1089 sym->flags &= ~SYMBOL_CHANGED;
1091 if (sym_is_choice(sym)) { // parse childs for getting final value
1093 struct symbol *def_sym = sym_get_choice_value(sym);
1094 struct menu *def_menu = NULL;
1096 row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
1098 for (child = menu->list; child; child = child->next) {
1099 if (menu_is_visible(child)
1100 && child->sym == def_sym)
1106 g_strdup(menu_get_prompt(def_menu));
1108 if (sym->flags & SYMBOL_CHOICEVAL)
1109 row[COL_BTNRAD] = GINT_TO_POINTER(TRUE);
1111 stype = sym_get_type(sym);
1114 if (GPOINTER_TO_INT(row[COL_PIXVIS]) == FALSE)
1115 row[COL_BTNVIS] = GINT_TO_POINTER(TRUE);
1116 if (sym_is_choice(sym))
1120 val = sym_get_tristate_value(sym);
1123 row[COL_NO] = g_strdup("N");
1124 row[COL_VALUE] = g_strdup("N");
1125 row[COL_BTNACT] = GINT_TO_POINTER(FALSE);
1126 row[COL_BTNINC] = GINT_TO_POINTER(FALSE);
1129 row[COL_MOD] = g_strdup("M");
1130 row[COL_VALUE] = g_strdup("M");
1131 row[COL_BTNINC] = GINT_TO_POINTER(TRUE);
1134 row[COL_YES] = g_strdup("Y");
1135 row[COL_VALUE] = g_strdup("Y");
1136 row[COL_BTNACT] = GINT_TO_POINTER(TRUE);
1137 row[COL_BTNINC] = GINT_TO_POINTER(FALSE);
1141 if (val != no && sym_tristate_within_range(sym, no))
1142 row[COL_NO] = g_strdup("_");
1143 if (val != mod && sym_tristate_within_range(sym, mod))
1144 row[COL_MOD] = g_strdup("_");
1145 if (val != yes && sym_tristate_within_range(sym, yes))
1146 row[COL_YES] = g_strdup("_");
1151 def = sym_get_string_value(sym);
1152 row[COL_VALUE] = g_strdup(def);
1153 row[COL_EDIT] = GINT_TO_POINTER(TRUE);
1154 row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
1162 /* Set the node content with a row of strings */
1163 static void set_node(GtkTreeIter * node, struct menu *menu, gchar ** row)
1169 pix = gdk_pixbuf_new_from_xpm_data((const char **)
1172 gdk_color_parse(row[COL_COLOR], &color);
1173 gdk_colormap_alloc_colors(gdk_colormap_get_system(), &color, 1,
1174 FALSE, FALSE, &success);
1176 gtk_tree_store_set(tree, node,
1177 COL_OPTION, row[COL_OPTION],
1178 COL_NAME, row[COL_NAME],
1179 COL_NO, row[COL_NO],
1180 COL_MOD, row[COL_MOD],
1181 COL_YES, row[COL_YES],
1182 COL_VALUE, row[COL_VALUE],
1183 COL_MENU, (gpointer) menu,
1185 COL_EDIT, GPOINTER_TO_INT(row[COL_EDIT]),
1187 COL_PIXVIS, GPOINTER_TO_INT(row[COL_PIXVIS]),
1188 COL_BTNVIS, GPOINTER_TO_INT(row[COL_BTNVIS]),
1189 COL_BTNACT, GPOINTER_TO_INT(row[COL_BTNACT]),
1190 COL_BTNINC, GPOINTER_TO_INT(row[COL_BTNINC]),
1191 COL_BTNRAD, GPOINTER_TO_INT(row[COL_BTNRAD]),
1194 g_object_unref(pix);
1198 /* Add a node to the tree */
1199 static void place_node(struct menu *menu, char **row)
1201 GtkTreeIter *parent = parents[indent - 1];
1202 GtkTreeIter *node = parents[indent];
1204 gtk_tree_store_append(tree, node, parent);
1205 set_node(node, menu, row);
1209 /* Find a node in the GTK+ tree */
1210 static GtkTreeIter found;
1213 * Find a menu in the GtkTree starting at parent.
1215 GtkTreeIter *gtktree_iter_find_node(GtkTreeIter * parent,
1216 struct menu *tofind)
1219 GtkTreeIter *child = &iter;
1223 valid = gtk_tree_model_iter_children(model2, child, parent);
1227 gtk_tree_model_get(model2, child, 6, &menu, -1);
1229 if (menu == tofind) {
1230 memcpy(&found, child, sizeof(GtkTreeIter));
1234 ret = gtktree_iter_find_node(child, tofind);
1238 valid = gtk_tree_model_iter_next(model2, child);
1246 * Update the tree by adding/removing entries
1247 * Does not change other nodes
1249 static void update_tree(struct menu *src, GtkTreeIter * dst)
1251 struct menu *child1;
1252 GtkTreeIter iter, tmp;
1253 GtkTreeIter *child2 = &iter;
1255 GtkTreeIter *sibling;
1257 struct menu *menu1, *menu2;
1259 if (src == &rootmenu)
1262 valid = gtk_tree_model_iter_children(model2, child2, dst);
1263 for (child1 = src->list; child1; child1 = child1->next) {
1270 gtk_tree_model_get(model2, child2, COL_MENU,
1273 menu2 = NULL; // force adding of a first child
1276 printf("%*c%s | %s\n", indent, ' ',
1277 menu1 ? menu_get_prompt(menu1) : "nil",
1278 menu2 ? menu_get_prompt(menu2) : "nil");
1281 if ((opt_mode == OPT_NORMAL && !menu_is_visible(child1)) ||
1282 (opt_mode == OPT_PROMPT && !menu_has_prompt(child1)) ||
1283 (opt_mode == OPT_ALL && !menu_get_prompt(child1))) {
1286 if (gtktree_iter_find_node(dst, menu1) != NULL) {
1287 memcpy(&tmp, child2, sizeof(GtkTreeIter));
1288 valid = gtk_tree_model_iter_next(model2,
1290 gtk_tree_store_remove(tree2, &tmp);
1292 return; /* next parent */
1294 goto reparse; /* next child */
1299 if (menu1 != menu2) {
1300 if (gtktree_iter_find_node(dst, menu1) == NULL) { // add node
1301 if (!valid && !menu2)
1305 gtk_tree_store_insert_before(tree2,
1308 set_node(child2, menu1, fill_row(menu1));
1311 } else { // remove node
1312 memcpy(&tmp, child2, sizeof(GtkTreeIter));
1313 valid = gtk_tree_model_iter_next(model2,
1315 gtk_tree_store_remove(tree2, &tmp);
1317 return; // next parent
1319 goto reparse; // next child
1321 } else if (sym && (sym->flags & SYMBOL_CHANGED)) {
1322 set_node(child2, menu1, fill_row(menu1));
1326 update_tree(child1, child2);
1329 valid = gtk_tree_model_iter_next(model2, child2);
1334 /* Display the whole tree (single/split/full view) */
1335 static void display_tree(struct menu *menu)
1338 struct property *prop;
1340 enum prop_type ptype;
1342 if (menu == &rootmenu) {
1344 current = &rootmenu;
1347 for (child = menu->list; child; child = child->next) {
1348 prop = child->prompt;
1350 ptype = prop ? prop->type : P_UNKNOWN;
1353 sym->flags &= ~SYMBOL_CHANGED;
1355 if ((view_mode == SPLIT_VIEW)
1356 && !(child->flags & MENU_ROOT) && (tree == tree1))
1359 if ((view_mode == SPLIT_VIEW) && (child->flags & MENU_ROOT)
1363 if ((opt_mode == OPT_NORMAL && menu_is_visible(child)) ||
1364 (opt_mode == OPT_PROMPT && menu_has_prompt(child)) ||
1365 (opt_mode == OPT_ALL && menu_get_prompt(child)))
1366 place_node(child, fill_row(child));
1368 printf("%*c%s: ", indent, ' ', menu_get_prompt(child));
1369 printf("%s", child->flags & MENU_ROOT ? "rootmenu | " : "");
1370 printf("%s", prop_get_type_name(ptype));
1373 printf("%s", sym_type_name(sym->type));
1375 printf("%s", dbg_sym_flags(sym->flags));
1380 if ((view_mode != FULL_VIEW) && (ptype == P_MENU)
1384 if (((menu != &rootmenu) && !(menu->flags & MENU_ROOT))
1385 || (view_mode == FULL_VIEW)
1386 || (view_mode == SPLIT_VIEW))*/
1388 /* Change paned position if the view is not in 'split mode' */
1389 if (view_mode == SINGLE_VIEW || view_mode == FULL_VIEW) {
1390 gtk_paned_set_position(GTK_PANED(hpaned), 0);
1393 if (((view_mode == SINGLE_VIEW) && (menu->flags & MENU_ROOT))
1394 || (view_mode == FULL_VIEW)
1395 || (view_mode == SPLIT_VIEW)) {
1397 display_tree(child);
1403 /* Display a part of the tree starting at current node (single/split view) */
1404 static void display_tree_part(void)
1407 gtk_tree_store_clear(tree2);
1408 if (view_mode == SINGLE_VIEW)
1409 display_tree(current);
1410 else if (view_mode == SPLIT_VIEW)
1411 display_tree(browsed);
1412 gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w));
1415 /* Display the list in the left frame (split view) */
1416 static void display_list(void)
1419 gtk_tree_store_clear(tree1);
1422 display_tree(&rootmenu);
1423 gtk_tree_view_expand_all(GTK_TREE_VIEW(tree1_w));
1427 void fixup_rootmenu(struct menu *menu)
1430 static int menu_cnt = 0;
1432 menu->flags |= MENU_ROOT;
1433 for (child = menu->list; child; child = child->next) {
1434 if (child->prompt && child->prompt->type == P_MENU) {
1436 fixup_rootmenu(child);
1438 } else if (!menu_cnt)
1439 fixup_rootmenu(child);
1445 int main(int ac, char *av[])
1456 //add_pixmap_directory (PACKAGE_DATA_DIR "/" PACKAGE "/pixmaps");
1457 //add_pixmap_directory (PACKAGE_SOURCE_DIR "/pixmaps");
1459 /* Determine GUI path */
1460 env = getenv(SRCTREE);
1462 glade_file = g_strconcat(env, "/scripts/kconfig/gconf.glade", NULL);
1463 else if (av[0][0] == '/')
1464 glade_file = g_strconcat(av[0], ".glade", NULL);
1466 glade_file = g_strconcat(g_get_current_dir(), "/", av[0], ".glade", NULL);
1469 if (ac > 1 && av[1][0] == '-') {
1475 conf_set_message_callback(NULL);
1479 printf("%s [-s] <config>\n", av[0]);
1487 fixup_rootmenu(&rootmenu);
1490 /* Load the interface and connect signals */
1491 init_main_window(glade_file);
1496 switch (view_mode) {
1498 display_tree_part();
1504 display_tree(&rootmenu);
1513 static void conf_changed(void)
1515 bool changed = conf_get_changed();
1516 gtk_widget_set_sensitive(save_btn, changed);
1517 gtk_widget_set_sensitive(save_menu_item, changed);