xref: /openbmc/linux/scripts/kconfig/gconf.c (revision d5cb9783536a41df9f9cba5b0a1d78047ed787f7)
1 /* Hey EMACS -*- linux-c -*- */
2 /*
3  *
4  * Copyright (C) 2002-2003 Romain Lievin <roms@tilp.info>
5  * Released under the terms of the GNU GPL v2.0.
6  *
7  */
8 
9 #ifdef HAVE_CONFIG_H
10 #  include <config.h>
11 #endif
12 
13 #include "lkc.h"
14 #include "images.c"
15 
16 #include <glade/glade.h>
17 #include <gtk/gtk.h>
18 #include <glib.h>
19 #include <gdk/gdkkeysyms.h>
20 
21 #include <stdio.h>
22 #include <string.h>
23 #include <unistd.h>
24 #include <time.h>
25 #include <stdlib.h>
26 
27 //#define DEBUG
28 
29 enum {
30 	SINGLE_VIEW, SPLIT_VIEW, FULL_VIEW
31 };
32 
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;
40 
41 static gboolean config_changed = FALSE;
42 
43 static char nohelp_text[] =
44     N_("Sorry, no help available for this option yet.\n");
45 
46 GtkWidget *main_wnd = NULL;
47 GtkWidget *tree1_w = NULL;	// left  frame
48 GtkWidget *tree2_w = NULL;	// right frame
49 GtkWidget *text_w = NULL;
50 GtkWidget *hpaned = NULL;
51 GtkWidget *vpaned = NULL;
52 GtkWidget *back_btn = NULL;
53 
54 GtkTextTag *tag1, *tag2;
55 GdkColor color;
56 
57 GtkTreeStore *tree1, *tree2, *tree;
58 GtkTreeModel *model1, *model2;
59 static GtkTreeIter *parents[256];
60 static gint indent;
61 
62 static struct menu *current; // current node for SINGLE view
63 static struct menu *browsed; // browsed node for SPLIT view
64 
65 enum {
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,
69 	COL_NUMBER
70 };
71 
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 
79 
80 /* Helping/Debugging Functions */
81 
82 
83 const char *dbg_print_stype(int val)
84 {
85 	static char buf[256];
86 
87 	bzero(buf, 256);
88 
89 	if (val == S_UNKNOWN)
90 		strcpy(buf, "unknown");
91 	if (val == S_BOOLEAN)
92 		strcpy(buf, "boolean");
93 	if (val == S_TRISTATE)
94 		strcpy(buf, "tristate");
95 	if (val == S_INT)
96 		strcpy(buf, "int");
97 	if (val == S_HEX)
98 		strcpy(buf, "hex");
99 	if (val == S_STRING)
100 		strcpy(buf, "string");
101 	if (val == S_OTHER)
102 		strcpy(buf, "other");
103 
104 #ifdef DEBUG
105 	printf("%s", buf);
106 #endif
107 
108 	return buf;
109 }
110 
111 const char *dbg_print_flags(int val)
112 {
113 	static char buf[256];
114 
115 	bzero(buf, 256);
116 
117 	if (val & SYMBOL_YES)
118 		strcat(buf, "yes/");
119 	if (val & SYMBOL_MOD)
120 		strcat(buf, "mod/");
121 	if (val & SYMBOL_NO)
122 		strcat(buf, "no/");
123 	if (val & SYMBOL_CONST)
124 		strcat(buf, "const/");
125 	if (val & SYMBOL_CHECK)
126 		strcat(buf, "check/");
127 	if (val & SYMBOL_CHOICE)
128 		strcat(buf, "choice/");
129 	if (val & SYMBOL_CHOICEVAL)
130 		strcat(buf, "choiceval/");
131 	if (val & SYMBOL_PRINTED)
132 		strcat(buf, "printed/");
133 	if (val & SYMBOL_VALID)
134 		strcat(buf, "valid/");
135 	if (val & SYMBOL_OPTIONAL)
136 		strcat(buf, "optional/");
137 	if (val & SYMBOL_WRITE)
138 		strcat(buf, "write/");
139 	if (val & SYMBOL_CHANGED)
140 		strcat(buf, "changed/");
141 	if (val & SYMBOL_NEW)
142 		strcat(buf, "new/");
143 	if (val & SYMBOL_AUTO)
144 		strcat(buf, "auto/");
145 
146 	buf[strlen(buf) - 1] = '\0';
147 #ifdef DEBUG
148 	printf("%s", buf);
149 #endif
150 
151 	return buf;
152 }
153 
154 const char *dbg_print_ptype(int val)
155 {
156 	static char buf[256];
157 
158 	bzero(buf, 256);
159 
160 	if (val == P_UNKNOWN)
161 		strcpy(buf, "unknown");
162 	if (val == P_PROMPT)
163 		strcpy(buf, "prompt");
164 	if (val == P_COMMENT)
165 		strcpy(buf, "comment");
166 	if (val == P_MENU)
167 		strcpy(buf, "menu");
168 	if (val == P_DEFAULT)
169 		strcpy(buf, "default");
170 	if (val == P_CHOICE)
171 		strcpy(buf, "choice");
172 
173 #ifdef DEBUG
174 	printf("%s", buf);
175 #endif
176 
177 	return buf;
178 }
179 
180 
181 void replace_button_icon(GladeXML * xml, GdkDrawable * window,
182 			 GtkStyle * style, gchar * btn_name, gchar ** xpm)
183 {
184 	GdkPixmap *pixmap;
185 	GdkBitmap *mask;
186 	GtkToolButton *button;
187 	GtkWidget *image;
188 
189 	pixmap = gdk_pixmap_create_from_xpm_d(window, &mask,
190 					      &style->bg[GTK_STATE_NORMAL],
191 					      xpm);
192 
193 	button = GTK_TOOL_BUTTON(glade_xml_get_widget(xml, btn_name));
194 	image = gtk_image_new_from_pixmap(pixmap, mask);
195 	gtk_widget_show(image);
196 	gtk_tool_button_set_icon_widget(button, image);
197 }
198 
199 /* Main Window Initialization */
200 void init_main_window(const gchar * glade_file)
201 {
202 	GladeXML *xml;
203 	GtkWidget *widget;
204 	GtkTextBuffer *txtbuf;
205 	char title[256];
206 	GtkStyle *style;
207 
208 	xml = glade_xml_new(glade_file, "window1", NULL);
209 	if (!xml)
210 		g_error(_("GUI loading failed !\n"));
211 	glade_xml_signal_autoconnect(xml);
212 
213 	main_wnd = glade_xml_get_widget(xml, "window1");
214 	hpaned = glade_xml_get_widget(xml, "hpaned1");
215 	vpaned = glade_xml_get_widget(xml, "vpaned1");
216 	tree1_w = glade_xml_get_widget(xml, "treeview1");
217 	tree2_w = glade_xml_get_widget(xml, "treeview2");
218 	text_w = glade_xml_get_widget(xml, "textview3");
219 
220 	back_btn = glade_xml_get_widget(xml, "button1");
221 	gtk_widget_set_sensitive(back_btn, FALSE);
222 
223 	widget = glade_xml_get_widget(xml, "show_name1");
224 	gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget,
225 				       show_name);
226 
227 	widget = glade_xml_get_widget(xml, "show_range1");
228 	gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget,
229 				       show_range);
230 
231 	widget = glade_xml_get_widget(xml, "show_data1");
232 	gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget,
233 				       show_value);
234 
235 	style = gtk_widget_get_style(main_wnd);
236 	widget = glade_xml_get_widget(xml, "toolbar1");
237 
238 #if 0	/* Use stock Gtk icons instead */
239 	replace_button_icon(xml, main_wnd->window, style,
240 			    "button1", (gchar **) xpm_back);
241 	replace_button_icon(xml, main_wnd->window, style,
242 			    "button2", (gchar **) xpm_load);
243 	replace_button_icon(xml, main_wnd->window, style,
244 			    "button3", (gchar **) xpm_save);
245 #endif
246 	replace_button_icon(xml, main_wnd->window, style,
247 			    "button4", (gchar **) xpm_single_view);
248 	replace_button_icon(xml, main_wnd->window, style,
249 			    "button5", (gchar **) xpm_split_view);
250 	replace_button_icon(xml, main_wnd->window, style,
251 			    "button6", (gchar **) xpm_tree_view);
252 
253 #if 0
254 	switch (view_mode) {
255 	case SINGLE_VIEW:
256 		widget = glade_xml_get_widget(xml, "button4");
257 		g_signal_emit_by_name(widget, "clicked");
258 		break;
259 	case SPLIT_VIEW:
260 		widget = glade_xml_get_widget(xml, "button5");
261 		g_signal_emit_by_name(widget, "clicked");
262 		break;
263 	case FULL_VIEW:
264 		widget = glade_xml_get_widget(xml, "button6");
265 		g_signal_emit_by_name(widget, "clicked");
266 		break;
267 	}
268 #endif
269 	txtbuf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w));
270 	tag1 = gtk_text_buffer_create_tag(txtbuf, "mytag1",
271 					  "foreground", "red",
272 					  "weight", PANGO_WEIGHT_BOLD,
273 					  NULL);
274 	tag2 = gtk_text_buffer_create_tag(txtbuf, "mytag2",
275 					  /*"style", PANGO_STYLE_OBLIQUE, */
276 					  NULL);
277 
278 	sprintf(title, _("Linux Kernel v%s Configuration"),
279 		getenv("KERNELRELEASE"));
280 	gtk_window_set_title(GTK_WINDOW(main_wnd), title);
281 
282 	gtk_widget_show(main_wnd);
283 }
284 
285 void init_tree_model(void)
286 {
287 	gint i;
288 
289 	tree = tree2 = gtk_tree_store_new(COL_NUMBER,
290 					  G_TYPE_STRING, G_TYPE_STRING,
291 					  G_TYPE_STRING, G_TYPE_STRING,
292 					  G_TYPE_STRING, G_TYPE_STRING,
293 					  G_TYPE_POINTER, GDK_TYPE_COLOR,
294 					  G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF,
295 					  G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
296 					  G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
297 					  G_TYPE_BOOLEAN);
298 	model2 = GTK_TREE_MODEL(tree2);
299 
300 	for (parents[0] = NULL, i = 1; i < 256; i++)
301 		parents[i] = (GtkTreeIter *) g_malloc(sizeof(GtkTreeIter));
302 
303 	tree1 = gtk_tree_store_new(COL_NUMBER,
304 				   G_TYPE_STRING, G_TYPE_STRING,
305 				   G_TYPE_STRING, G_TYPE_STRING,
306 				   G_TYPE_STRING, G_TYPE_STRING,
307 				   G_TYPE_POINTER, GDK_TYPE_COLOR,
308 				   G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF,
309 				   G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
310 				   G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
311 				   G_TYPE_BOOLEAN);
312 	model1 = GTK_TREE_MODEL(tree1);
313 }
314 
315 void init_left_tree(void)
316 {
317 	GtkTreeView *view = GTK_TREE_VIEW(tree1_w);
318 	GtkCellRenderer *renderer;
319 	GtkTreeSelection *sel;
320 	GtkTreeViewColumn *column;
321 
322 	gtk_tree_view_set_model(view, model1);
323 	gtk_tree_view_set_headers_visible(view, TRUE);
324 	gtk_tree_view_set_rules_hint(view, FALSE);
325 
326 	column = gtk_tree_view_column_new();
327 	gtk_tree_view_append_column(view, column);
328 	gtk_tree_view_column_set_title(column, _("Options"));
329 
330 	renderer = gtk_cell_renderer_toggle_new();
331 	gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
332 					renderer, FALSE);
333 	gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
334 					    renderer,
335 					    "active", COL_BTNACT,
336 					    "inconsistent", COL_BTNINC,
337 					    "visible", COL_BTNVIS,
338 					    "radio", COL_BTNRAD, NULL);
339 	renderer = gtk_cell_renderer_text_new();
340 	gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
341 					renderer, FALSE);
342 	gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
343 					    renderer,
344 					    "text", COL_OPTION,
345 					    "foreground-gdk",
346 					    COL_COLOR, NULL);
347 
348 	sel = gtk_tree_view_get_selection(view);
349 	gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
350 	gtk_widget_realize(tree1_w);
351 }
352 
353 static void renderer_edited(GtkCellRendererText * cell,
354 			    const gchar * path_string,
355 			    const gchar * new_text, gpointer user_data);
356 static void renderer_toggled(GtkCellRendererToggle * cellrenderertoggle,
357 			     gchar * arg1, gpointer user_data);
358 
359 void init_right_tree(void)
360 {
361 	GtkTreeView *view = GTK_TREE_VIEW(tree2_w);
362 	GtkCellRenderer *renderer;
363 	GtkTreeSelection *sel;
364 	GtkTreeViewColumn *column;
365 	gint i;
366 
367 	gtk_tree_view_set_model(view, model2);
368 	gtk_tree_view_set_headers_visible(view, TRUE);
369 	gtk_tree_view_set_rules_hint(view, FALSE);
370 
371 	column = gtk_tree_view_column_new();
372 	gtk_tree_view_append_column(view, column);
373 	gtk_tree_view_column_set_title(column, _("Options"));
374 
375 	renderer = gtk_cell_renderer_pixbuf_new();
376 	gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
377 					renderer, FALSE);
378 	gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
379 					    renderer,
380 					    "pixbuf", COL_PIXBUF,
381 					    "visible", COL_PIXVIS, NULL);
382 	renderer = gtk_cell_renderer_toggle_new();
383 	gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
384 					renderer, FALSE);
385 	gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
386 					    renderer,
387 					    "active", COL_BTNACT,
388 					    "inconsistent", COL_BTNINC,
389 					    "visible", COL_BTNVIS,
390 					    "radio", COL_BTNRAD, NULL);
391 	/*g_signal_connect(G_OBJECT(renderer), "toggled",
392 	   G_CALLBACK(renderer_toggled), NULL); */
393 	renderer = gtk_cell_renderer_text_new();
394 	gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
395 					renderer, FALSE);
396 	gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
397 					    renderer,
398 					    "text", COL_OPTION,
399 					    "foreground-gdk",
400 					    COL_COLOR, NULL);
401 
402 	renderer = gtk_cell_renderer_text_new();
403 	gtk_tree_view_insert_column_with_attributes(view, -1,
404 						    _("Name"), renderer,
405 						    "text", COL_NAME,
406 						    "foreground-gdk",
407 						    COL_COLOR, NULL);
408 	renderer = gtk_cell_renderer_text_new();
409 	gtk_tree_view_insert_column_with_attributes(view, -1,
410 						    "N", renderer,
411 						    "text", COL_NO,
412 						    "foreground-gdk",
413 						    COL_COLOR, NULL);
414 	renderer = gtk_cell_renderer_text_new();
415 	gtk_tree_view_insert_column_with_attributes(view, -1,
416 						    "M", renderer,
417 						    "text", COL_MOD,
418 						    "foreground-gdk",
419 						    COL_COLOR, NULL);
420 	renderer = gtk_cell_renderer_text_new();
421 	gtk_tree_view_insert_column_with_attributes(view, -1,
422 						    "Y", renderer,
423 						    "text", COL_YES,
424 						    "foreground-gdk",
425 						    COL_COLOR, NULL);
426 	renderer = gtk_cell_renderer_text_new();
427 	gtk_tree_view_insert_column_with_attributes(view, -1,
428 						    _("Value"), renderer,
429 						    "text", COL_VALUE,
430 						    "editable",
431 						    COL_EDIT,
432 						    "foreground-gdk",
433 						    COL_COLOR, NULL);
434 	g_signal_connect(G_OBJECT(renderer), "edited",
435 			 G_CALLBACK(renderer_edited), NULL);
436 
437 	column = gtk_tree_view_get_column(view, COL_NAME);
438 	gtk_tree_view_column_set_visible(column, show_name);
439 	column = gtk_tree_view_get_column(view, COL_NO);
440 	gtk_tree_view_column_set_visible(column, show_range);
441 	column = gtk_tree_view_get_column(view, COL_MOD);
442 	gtk_tree_view_column_set_visible(column, show_range);
443 	column = gtk_tree_view_get_column(view, COL_YES);
444 	gtk_tree_view_column_set_visible(column, show_range);
445 	column = gtk_tree_view_get_column(view, COL_VALUE);
446 	gtk_tree_view_column_set_visible(column, show_value);
447 
448 	if (resizeable) {
449 		for (i = 0; i < COL_VALUE; i++) {
450 			column = gtk_tree_view_get_column(view, i);
451 			gtk_tree_view_column_set_resizable(column, TRUE);
452 		}
453 	}
454 
455 	sel = gtk_tree_view_get_selection(view);
456 	gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
457 }
458 
459 
460 /* Utility Functions */
461 
462 
463 static void text_insert_help(struct menu *menu)
464 {
465 	GtkTextBuffer *buffer;
466 	GtkTextIter start, end;
467 	const char *prompt = menu_get_prompt(menu);
468 	gchar *name;
469 	const char *help = _(nohelp_text);
470 
471 	if (!menu->sym)
472 		help = "";
473 	else if (menu->sym->help)
474 		help = _(menu->sym->help);
475 
476 	if (menu->sym && menu->sym->name)
477 		name = g_strdup_printf(_(menu->sym->name));
478 	else
479 		name = g_strdup("");
480 
481 	buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w));
482 	gtk_text_buffer_get_bounds(buffer, &start, &end);
483 	gtk_text_buffer_delete(buffer, &start, &end);
484 	gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_w), 15);
485 
486 	gtk_text_buffer_get_end_iter(buffer, &end);
487 	gtk_text_buffer_insert_with_tags(buffer, &end, prompt, -1, tag1,
488 					 NULL);
489 	gtk_text_buffer_insert_at_cursor(buffer, " ", 1);
490 	gtk_text_buffer_get_end_iter(buffer, &end);
491 	gtk_text_buffer_insert_with_tags(buffer, &end, name, -1, tag1,
492 					 NULL);
493 	gtk_text_buffer_insert_at_cursor(buffer, "\n\n", 2);
494 	gtk_text_buffer_get_end_iter(buffer, &end);
495 	gtk_text_buffer_insert_with_tags(buffer, &end, help, -1, tag2,
496 					 NULL);
497 }
498 
499 
500 static void text_insert_msg(const char *title, const char *message)
501 {
502 	GtkTextBuffer *buffer;
503 	GtkTextIter start, end;
504 	const char *msg = message;
505 
506 	buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w));
507 	gtk_text_buffer_get_bounds(buffer, &start, &end);
508 	gtk_text_buffer_delete(buffer, &start, &end);
509 	gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_w), 15);
510 
511 	gtk_text_buffer_get_end_iter(buffer, &end);
512 	gtk_text_buffer_insert_with_tags(buffer, &end, title, -1, tag1,
513 					 NULL);
514 	gtk_text_buffer_insert_at_cursor(buffer, "\n\n", 2);
515 	gtk_text_buffer_get_end_iter(buffer, &end);
516 	gtk_text_buffer_insert_with_tags(buffer, &end, msg, -1, tag2,
517 					 NULL);
518 }
519 
520 
521 /* Main Windows Callbacks */
522 
523 void on_save1_activate(GtkMenuItem * menuitem, gpointer user_data);
524 gboolean on_window1_delete_event(GtkWidget * widget, GdkEvent * event,
525 				 gpointer user_data)
526 {
527 	GtkWidget *dialog, *label;
528 	gint result;
529 
530 	if (config_changed == FALSE)
531 		return FALSE;
532 
533 	dialog = gtk_dialog_new_with_buttons(_("Warning !"),
534 					     GTK_WINDOW(main_wnd),
535 					     (GtkDialogFlags)
536 					     (GTK_DIALOG_MODAL |
537 					      GTK_DIALOG_DESTROY_WITH_PARENT),
538 					     GTK_STOCK_OK,
539 					     GTK_RESPONSE_YES,
540 					     GTK_STOCK_NO,
541 					     GTK_RESPONSE_NO,
542 					     GTK_STOCK_CANCEL,
543 					     GTK_RESPONSE_CANCEL, NULL);
544 	gtk_dialog_set_default_response(GTK_DIALOG(dialog),
545 					GTK_RESPONSE_CANCEL);
546 
547 	label = gtk_label_new(_("\nSave configuration ?\n"));
548 	gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), label);
549 	gtk_widget_show(label);
550 
551 	result = gtk_dialog_run(GTK_DIALOG(dialog));
552 	switch (result) {
553 	case GTK_RESPONSE_YES:
554 		on_save1_activate(NULL, NULL);
555 		return FALSE;
556 	case GTK_RESPONSE_NO:
557 		return FALSE;
558 	case GTK_RESPONSE_CANCEL:
559 	case GTK_RESPONSE_DELETE_EVENT:
560 	default:
561 		gtk_widget_destroy(dialog);
562 		return TRUE;
563 	}
564 
565 	return FALSE;
566 }
567 
568 
569 void on_window1_destroy(GtkObject * object, gpointer user_data)
570 {
571 	gtk_main_quit();
572 }
573 
574 
575 void
576 on_window1_size_request(GtkWidget * widget,
577 			GtkRequisition * requisition, gpointer user_data)
578 {
579 	static gint old_h;
580 	gint w, h;
581 
582 	if (widget->window == NULL)
583 		gtk_window_get_default_size(GTK_WINDOW(main_wnd), &w, &h);
584 	else
585 		gdk_window_get_size(widget->window, &w, &h);
586 
587 	if (h == old_h)
588 		return;
589 	old_h = h;
590 
591 	gtk_paned_set_position(GTK_PANED(vpaned), 2 * h / 3);
592 }
593 
594 
595 /* Menu & Toolbar Callbacks */
596 
597 
598 static void
599 load_filename(GtkFileSelection * file_selector, gpointer user_data)
600 {
601 	const gchar *fn;
602 
603 	fn = gtk_file_selection_get_filename(GTK_FILE_SELECTION
604 					     (user_data));
605 
606 	if (conf_read(fn))
607 		text_insert_msg(_("Error"), _("Unable to load configuration !"));
608 	else
609 		display_tree(&rootmenu);
610 }
611 
612 void on_load1_activate(GtkMenuItem * menuitem, gpointer user_data)
613 {
614 	GtkWidget *fs;
615 
616 	fs = gtk_file_selection_new(_("Load file..."));
617 	g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs)->ok_button),
618 			 "clicked",
619 			 G_CALLBACK(load_filename), (gpointer) fs);
620 	g_signal_connect_swapped(GTK_OBJECT
621 				 (GTK_FILE_SELECTION(fs)->ok_button),
622 				 "clicked", G_CALLBACK(gtk_widget_destroy),
623 				 (gpointer) fs);
624 	g_signal_connect_swapped(GTK_OBJECT
625 				 (GTK_FILE_SELECTION(fs)->cancel_button),
626 				 "clicked", G_CALLBACK(gtk_widget_destroy),
627 				 (gpointer) fs);
628 	gtk_widget_show(fs);
629 }
630 
631 
632 void on_save1_activate(GtkMenuItem * menuitem, gpointer user_data)
633 {
634 	if (conf_write(NULL))
635 		text_insert_msg(_("Error"), _("Unable to save configuration !"));
636 
637 	config_changed = FALSE;
638 }
639 
640 
641 static void
642 store_filename(GtkFileSelection * file_selector, gpointer user_data)
643 {
644 	const gchar *fn;
645 
646 	fn = gtk_file_selection_get_filename(GTK_FILE_SELECTION
647 					     (user_data));
648 
649 	if (conf_write(fn))
650 		text_insert_msg(_("Error"), _("Unable to save configuration !"));
651 
652 	gtk_widget_destroy(GTK_WIDGET(user_data));
653 }
654 
655 void on_save_as1_activate(GtkMenuItem * menuitem, gpointer user_data)
656 {
657 	GtkWidget *fs;
658 
659 	fs = gtk_file_selection_new(_("Save file as..."));
660 	g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs)->ok_button),
661 			 "clicked",
662 			 G_CALLBACK(store_filename), (gpointer) fs);
663 	g_signal_connect_swapped(GTK_OBJECT
664 				 (GTK_FILE_SELECTION(fs)->ok_button),
665 				 "clicked", G_CALLBACK(gtk_widget_destroy),
666 				 (gpointer) fs);
667 	g_signal_connect_swapped(GTK_OBJECT
668 				 (GTK_FILE_SELECTION(fs)->cancel_button),
669 				 "clicked", G_CALLBACK(gtk_widget_destroy),
670 				 (gpointer) fs);
671 	gtk_widget_show(fs);
672 }
673 
674 
675 void on_quit1_activate(GtkMenuItem * menuitem, gpointer user_data)
676 {
677 	if (!on_window1_delete_event(NULL, NULL, NULL))
678 		gtk_widget_destroy(GTK_WIDGET(main_wnd));
679 }
680 
681 
682 void on_show_name1_activate(GtkMenuItem * menuitem, gpointer user_data)
683 {
684 	GtkTreeViewColumn *col;
685 
686 	show_name = GTK_CHECK_MENU_ITEM(menuitem)->active;
687 	col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_NAME);
688 	if (col)
689 		gtk_tree_view_column_set_visible(col, show_name);
690 }
691 
692 
693 void on_show_range1_activate(GtkMenuItem * menuitem, gpointer user_data)
694 {
695 	GtkTreeViewColumn *col;
696 
697 	show_range = GTK_CHECK_MENU_ITEM(menuitem)->active;
698 	col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_NO);
699 	if (col)
700 		gtk_tree_view_column_set_visible(col, show_range);
701 	col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_MOD);
702 	if (col)
703 		gtk_tree_view_column_set_visible(col, show_range);
704 	col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_YES);
705 	if (col)
706 		gtk_tree_view_column_set_visible(col, show_range);
707 
708 }
709 
710 
711 void on_show_data1_activate(GtkMenuItem * menuitem, gpointer user_data)
712 {
713 	GtkTreeViewColumn *col;
714 
715 	show_value = GTK_CHECK_MENU_ITEM(menuitem)->active;
716 	col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_VALUE);
717 	if (col)
718 		gtk_tree_view_column_set_visible(col, show_value);
719 }
720 
721 
722 void
723 on_show_all_options1_activate(GtkMenuItem * menuitem, gpointer user_data)
724 {
725 	show_all = GTK_CHECK_MENU_ITEM(menuitem)->active;
726 
727 	gtk_tree_store_clear(tree2);
728 	display_tree(&rootmenu);	// instead of update_tree to speed-up
729 }
730 
731 
732 void
733 on_show_debug_info1_activate(GtkMenuItem * menuitem, gpointer user_data)
734 {
735 	show_debug = GTK_CHECK_MENU_ITEM(menuitem)->active;
736 	update_tree(&rootmenu, NULL);
737 }
738 
739 
740 void on_introduction1_activate(GtkMenuItem * menuitem, gpointer user_data)
741 {
742 	GtkWidget *dialog;
743 	const gchar *intro_text = _(
744 	    "Welcome to gkc, the GTK+ graphical kernel configuration tool\n"
745 	    "for Linux.\n"
746 	    "For each option, a blank box indicates the feature is disabled, a\n"
747 	    "check indicates it is enabled, and a dot indicates that it is to\n"
748 	    "be compiled as a module.  Clicking on the box will cycle through the three states.\n"
749 	    "\n"
750 	    "If you do not see an option (e.g., a device driver) that you\n"
751 	    "believe should be present, try turning on Show All Options\n"
752 	    "under the Options menu.\n"
753 	    "Although there is no cross reference yet to help you figure out\n"
754 	    "what other options must be enabled to support the option you\n"
755 	    "are interested in, you can still view the help of a grayed-out\n"
756 	    "option.\n"
757 	    "\n"
758 	    "Toggling Show Debug Info under the Options menu will show \n"
759 	    "the dependencies, which you can then match by examining other options.");
760 
761 	dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
762 					GTK_DIALOG_DESTROY_WITH_PARENT,
763 					GTK_MESSAGE_INFO,
764 					GTK_BUTTONS_CLOSE, intro_text);
765 	g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
766 				 G_CALLBACK(gtk_widget_destroy),
767 				 GTK_OBJECT(dialog));
768 	gtk_widget_show_all(dialog);
769 }
770 
771 
772 void on_about1_activate(GtkMenuItem * menuitem, gpointer user_data)
773 {
774 	GtkWidget *dialog;
775 	const gchar *about_text =
776 	    _("gkc is copyright (c) 2002 Romain Lievin <roms@lpg.ticalc.org>.\n"
777 	      "Based on the source code from Roman Zippel.\n");
778 
779 	dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
780 					GTK_DIALOG_DESTROY_WITH_PARENT,
781 					GTK_MESSAGE_INFO,
782 					GTK_BUTTONS_CLOSE, about_text);
783 	g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
784 				 G_CALLBACK(gtk_widget_destroy),
785 				 GTK_OBJECT(dialog));
786 	gtk_widget_show_all(dialog);
787 }
788 
789 
790 void on_license1_activate(GtkMenuItem * menuitem, gpointer user_data)
791 {
792 	GtkWidget *dialog;
793 	const gchar *license_text =
794 	    _("gkc is released under the terms of the GNU GPL v2.\n"
795 	      "For more information, please see the source code or\n"
796 	      "visit http://www.fsf.org/licenses/licenses.html\n");
797 
798 	dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
799 					GTK_DIALOG_DESTROY_WITH_PARENT,
800 					GTK_MESSAGE_INFO,
801 					GTK_BUTTONS_CLOSE, license_text);
802 	g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
803 				 G_CALLBACK(gtk_widget_destroy),
804 				 GTK_OBJECT(dialog));
805 	gtk_widget_show_all(dialog);
806 }
807 
808 
809 void on_back_clicked(GtkButton * button, gpointer user_data)
810 {
811 	enum prop_type ptype;
812 
813 	current = current->parent;
814 	ptype = current->prompt ? current->prompt->type : P_UNKNOWN;
815 	if (ptype != P_MENU)
816 		current = current->parent;
817 	display_tree_part();
818 
819 	if (current == &rootmenu)
820 		gtk_widget_set_sensitive(back_btn, FALSE);
821 }
822 
823 
824 void on_load_clicked(GtkButton * button, gpointer user_data)
825 {
826 	on_load1_activate(NULL, user_data);
827 }
828 
829 
830 void on_save_clicked(GtkButton * button, gpointer user_data)
831 {
832 	on_save1_activate(NULL, user_data);
833 }
834 
835 
836 void on_single_clicked(GtkButton * button, gpointer user_data)
837 {
838 	view_mode = SINGLE_VIEW;
839 	gtk_paned_set_position(GTK_PANED(hpaned), 0);
840 	gtk_widget_hide(tree1_w);
841 	current = &rootmenu;
842 	display_tree_part();
843 }
844 
845 
846 void on_split_clicked(GtkButton * button, gpointer user_data)
847 {
848 	gint w, h;
849 	view_mode = SPLIT_VIEW;
850 	gtk_widget_show(tree1_w);
851 	gtk_window_get_default_size(GTK_WINDOW(main_wnd), &w, &h);
852 	gtk_paned_set_position(GTK_PANED(hpaned), w / 2);
853 	if (tree2)
854 		gtk_tree_store_clear(tree2);
855 	display_list();
856 
857 	/* Disable back btn, like in full mode. */
858 	gtk_widget_set_sensitive(back_btn, FALSE);
859 }
860 
861 
862 void on_full_clicked(GtkButton * button, gpointer user_data)
863 {
864 	view_mode = FULL_VIEW;
865 	gtk_paned_set_position(GTK_PANED(hpaned), 0);
866 	gtk_widget_hide(tree1_w);
867 	if (tree2)
868 		gtk_tree_store_clear(tree2);
869 	display_tree(&rootmenu);
870 	gtk_widget_set_sensitive(back_btn, FALSE);
871 }
872 
873 
874 void on_collapse_clicked(GtkButton * button, gpointer user_data)
875 {
876 	gtk_tree_view_collapse_all(GTK_TREE_VIEW(tree2_w));
877 }
878 
879 
880 void on_expand_clicked(GtkButton * button, gpointer user_data)
881 {
882 	gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w));
883 }
884 
885 
886 /* CTree Callbacks */
887 
888 /* Change hex/int/string value in the cell */
889 static void renderer_edited(GtkCellRendererText * cell,
890 			    const gchar * path_string,
891 			    const gchar * new_text, gpointer user_data)
892 {
893 	GtkTreePath *path = gtk_tree_path_new_from_string(path_string);
894 	GtkTreeIter iter;
895 	const char *old_def, *new_def;
896 	struct menu *menu;
897 	struct symbol *sym;
898 
899 	if (!gtk_tree_model_get_iter(model2, &iter, path))
900 		return;
901 
902 	gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
903 	sym = menu->sym;
904 
905 	gtk_tree_model_get(model2, &iter, COL_VALUE, &old_def, -1);
906 	new_def = new_text;
907 
908 	sym_set_string_value(sym, new_def);
909 
910 	config_changed = TRUE;
911 	update_tree(&rootmenu, NULL);
912 
913 	gtk_tree_path_free(path);
914 }
915 
916 /* Change the value of a symbol and update the tree */
917 static void change_sym_value(struct menu *menu, gint col)
918 {
919 	struct symbol *sym = menu->sym;
920 	tristate oldval, newval;
921 
922 	if (!sym)
923 		return;
924 
925 	if (col == COL_NO)
926 		newval = no;
927 	else if (col == COL_MOD)
928 		newval = mod;
929 	else if (col == COL_YES)
930 		newval = yes;
931 	else
932 		return;
933 
934 	switch (sym_get_type(sym)) {
935 	case S_BOOLEAN:
936 	case S_TRISTATE:
937 		oldval = sym_get_tristate_value(sym);
938 		if (!sym_tristate_within_range(sym, newval))
939 			newval = yes;
940 		sym_set_tristate_value(sym, newval);
941 		config_changed = TRUE;
942 		if (view_mode == FULL_VIEW)
943 			update_tree(&rootmenu, NULL);
944 		else if (view_mode == SPLIT_VIEW) {
945 			update_tree(browsed, NULL);
946 			display_list();
947 		}
948 		else if (view_mode == SINGLE_VIEW)
949 			display_tree_part();	//fixme: keep exp/coll
950 		break;
951 	case S_INT:
952 	case S_HEX:
953 	case S_STRING:
954 	default:
955 		break;
956 	}
957 }
958 
959 static void toggle_sym_value(struct menu *menu)
960 {
961 	if (!menu->sym)
962 		return;
963 
964 	sym_toggle_tristate_value(menu->sym);
965 	if (view_mode == FULL_VIEW)
966 		update_tree(&rootmenu, NULL);
967 	else if (view_mode == SPLIT_VIEW) {
968 		update_tree(browsed, NULL);
969 		display_list();
970 	}
971 	else if (view_mode == SINGLE_VIEW)
972 		display_tree_part();	//fixme: keep exp/coll
973 }
974 
975 static void renderer_toggled(GtkCellRendererToggle * cell,
976 			     gchar * path_string, gpointer user_data)
977 {
978 	GtkTreePath *path, *sel_path = NULL;
979 	GtkTreeIter iter, sel_iter;
980 	GtkTreeSelection *sel;
981 	struct menu *menu;
982 
983 	path = gtk_tree_path_new_from_string(path_string);
984 	if (!gtk_tree_model_get_iter(model2, &iter, path))
985 		return;
986 
987 	sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree2_w));
988 	if (gtk_tree_selection_get_selected(sel, NULL, &sel_iter))
989 		sel_path = gtk_tree_model_get_path(model2, &sel_iter);
990 	if (!sel_path)
991 		goto out1;
992 	if (gtk_tree_path_compare(path, sel_path))
993 		goto out2;
994 
995 	gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
996 	toggle_sym_value(menu);
997 
998       out2:
999 	gtk_tree_path_free(sel_path);
1000       out1:
1001 	gtk_tree_path_free(path);
1002 }
1003 
1004 static gint column2index(GtkTreeViewColumn * column)
1005 {
1006 	gint i;
1007 
1008 	for (i = 0; i < COL_NUMBER; i++) {
1009 		GtkTreeViewColumn *col;
1010 
1011 		col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), i);
1012 		if (col == column)
1013 			return i;
1014 	}
1015 
1016 	return -1;
1017 }
1018 
1019 
1020 /* User click: update choice (full) or goes down (single) */
1021 gboolean
1022 on_treeview2_button_press_event(GtkWidget * widget,
1023 				GdkEventButton * event, gpointer user_data)
1024 {
1025 	GtkTreeView *view = GTK_TREE_VIEW(widget);
1026 	GtkTreePath *path;
1027 	GtkTreeViewColumn *column;
1028 	GtkTreeIter iter;
1029 	struct menu *menu;
1030 	gint col;
1031 
1032 #if GTK_CHECK_VERSION(2,1,4) // bug in ctree with earlier version of GTK
1033 	gint tx = (gint) event->x;
1034 	gint ty = (gint) event->y;
1035 	gint cx, cy;
1036 
1037 	gtk_tree_view_get_path_at_pos(view, tx, ty, &path, &column, &cx,
1038 				      &cy);
1039 #else
1040 	gtk_tree_view_get_cursor(view, &path, &column);
1041 #endif
1042 	if (path == NULL)
1043 		return FALSE;
1044 
1045 	if (!gtk_tree_model_get_iter(model2, &iter, path))
1046 		return FALSE;
1047 	gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
1048 
1049 	col = column2index(column);
1050 	if (event->type == GDK_2BUTTON_PRESS) {
1051 		enum prop_type ptype;
1052 		ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
1053 
1054 		if (ptype == P_MENU && view_mode != FULL_VIEW && col == COL_OPTION) {
1055 			// goes down into menu
1056 			current = menu;
1057 			display_tree_part();
1058 			gtk_widget_set_sensitive(back_btn, TRUE);
1059 		} else if ((col == COL_OPTION)) {
1060 			toggle_sym_value(menu);
1061 			gtk_tree_view_expand_row(view, path, TRUE);
1062 		}
1063 	} else {
1064 		if (col == COL_VALUE) {
1065 			toggle_sym_value(menu);
1066 			gtk_tree_view_expand_row(view, path, TRUE);
1067 		} else if (col == COL_NO || col == COL_MOD
1068 			   || col == COL_YES) {
1069 			change_sym_value(menu, col);
1070 			gtk_tree_view_expand_row(view, path, TRUE);
1071 		}
1072 	}
1073 
1074 	return FALSE;
1075 }
1076 
1077 /* Key pressed: update choice */
1078 gboolean
1079 on_treeview2_key_press_event(GtkWidget * widget,
1080 			     GdkEventKey * event, gpointer user_data)
1081 {
1082 	GtkTreeView *view = GTK_TREE_VIEW(widget);
1083 	GtkTreePath *path;
1084 	GtkTreeViewColumn *column;
1085 	GtkTreeIter iter;
1086 	struct menu *menu;
1087 	gint col;
1088 
1089 	gtk_tree_view_get_cursor(view, &path, &column);
1090 	if (path == NULL)
1091 		return FALSE;
1092 
1093 	if (event->keyval == GDK_space) {
1094 		if (gtk_tree_view_row_expanded(view, path))
1095 			gtk_tree_view_collapse_row(view, path);
1096 		else
1097 			gtk_tree_view_expand_row(view, path, FALSE);
1098 		return TRUE;
1099 	}
1100 	if (event->keyval == GDK_KP_Enter) {
1101 	}
1102 	if (widget == tree1_w)
1103 		return FALSE;
1104 
1105 	gtk_tree_model_get_iter(model2, &iter, path);
1106 	gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
1107 
1108 	if (!strcasecmp(event->string, "n"))
1109 		col = COL_NO;
1110 	else if (!strcasecmp(event->string, "m"))
1111 		col = COL_MOD;
1112 	else if (!strcasecmp(event->string, "y"))
1113 		col = COL_YES;
1114 	else
1115 		col = -1;
1116 	change_sym_value(menu, col);
1117 
1118 	return FALSE;
1119 }
1120 
1121 
1122 /* Row selection changed: update help */
1123 void
1124 on_treeview2_cursor_changed(GtkTreeView * treeview, gpointer user_data)
1125 {
1126 	GtkTreeSelection *selection;
1127 	GtkTreeIter iter;
1128 	struct menu *menu;
1129 
1130 	selection = gtk_tree_view_get_selection(treeview);
1131 	if (gtk_tree_selection_get_selected(selection, &model2, &iter)) {
1132 		gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
1133 		text_insert_help(menu);
1134 	}
1135 }
1136 
1137 
1138 /* User click: display sub-tree in the right frame. */
1139 gboolean
1140 on_treeview1_button_press_event(GtkWidget * widget,
1141 				GdkEventButton * event, gpointer user_data)
1142 {
1143 	GtkTreeView *view = GTK_TREE_VIEW(widget);
1144 	GtkTreePath *path;
1145 	GtkTreeViewColumn *column;
1146 	GtkTreeIter iter;
1147 	struct menu *menu;
1148 
1149 	gint tx = (gint) event->x;
1150 	gint ty = (gint) event->y;
1151 	gint cx, cy;
1152 
1153 	gtk_tree_view_get_path_at_pos(view, tx, ty, &path, &column, &cx,
1154 				      &cy);
1155 	if (path == NULL)
1156 		return FALSE;
1157 
1158 	gtk_tree_model_get_iter(model1, &iter, path);
1159 	gtk_tree_model_get(model1, &iter, COL_MENU, &menu, -1);
1160 
1161 	if (event->type == GDK_2BUTTON_PRESS) {
1162 		toggle_sym_value(menu);
1163 		current = menu;
1164 		display_tree_part();
1165 	} else {
1166 		browsed = menu;
1167 		display_tree_part();
1168 	}
1169 
1170 	gtk_widget_realize(tree2_w);
1171 	gtk_tree_view_set_cursor(view, path, NULL, FALSE);
1172 	gtk_widget_grab_focus(tree2_w);
1173 
1174 	return FALSE;
1175 }
1176 
1177 
1178 /* Fill a row of strings */
1179 static gchar **fill_row(struct menu *menu)
1180 {
1181 	static gchar *row[COL_NUMBER];
1182 	struct symbol *sym = menu->sym;
1183 	const char *def;
1184 	int stype;
1185 	tristate val;
1186 	enum prop_type ptype;
1187 	int i;
1188 
1189 	for (i = COL_OPTION; i <= COL_COLOR; i++)
1190 		g_free(row[i]);
1191 	bzero(row, sizeof(row));
1192 
1193 	row[COL_OPTION] =
1194 	    g_strdup_printf("%s %s", menu_get_prompt(menu),
1195 			    sym ? (sym->
1196 				   flags & SYMBOL_NEW ? "(NEW)" : "") :
1197 			    "");
1198 
1199 	if (show_all && !menu_is_visible(menu))
1200 		row[COL_COLOR] = g_strdup("DarkGray");
1201 	else
1202 		row[COL_COLOR] = g_strdup("Black");
1203 
1204 	ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
1205 	switch (ptype) {
1206 	case P_MENU:
1207 		row[COL_PIXBUF] = (gchar *) xpm_menu;
1208 		if (view_mode == SINGLE_VIEW)
1209 			row[COL_PIXVIS] = GINT_TO_POINTER(TRUE);
1210 		row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
1211 		break;
1212 	case P_COMMENT:
1213 		row[COL_PIXBUF] = (gchar *) xpm_void;
1214 		row[COL_PIXVIS] = GINT_TO_POINTER(FALSE);
1215 		row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
1216 		break;
1217 	default:
1218 		row[COL_PIXBUF] = (gchar *) xpm_void;
1219 		row[COL_PIXVIS] = GINT_TO_POINTER(FALSE);
1220 		row[COL_BTNVIS] = GINT_TO_POINTER(TRUE);
1221 		break;
1222 	}
1223 
1224 	if (!sym)
1225 		return row;
1226 	row[COL_NAME] = g_strdup(sym->name);
1227 
1228 	sym_calc_value(sym);
1229 	sym->flags &= ~SYMBOL_CHANGED;
1230 
1231 	if (sym_is_choice(sym)) {	// parse childs for getting final value
1232 		struct menu *child;
1233 		struct symbol *def_sym = sym_get_choice_value(sym);
1234 		struct menu *def_menu = NULL;
1235 
1236 		row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
1237 
1238 		for (child = menu->list; child; child = child->next) {
1239 			if (menu_is_visible(child)
1240 			    && child->sym == def_sym)
1241 				def_menu = child;
1242 		}
1243 
1244 		if (def_menu)
1245 			row[COL_VALUE] =
1246 			    g_strdup(menu_get_prompt(def_menu));
1247 	}
1248 	if (sym->flags & SYMBOL_CHOICEVAL)
1249 		row[COL_BTNRAD] = GINT_TO_POINTER(TRUE);
1250 
1251 	stype = sym_get_type(sym);
1252 	switch (stype) {
1253 	case S_BOOLEAN:
1254 		if (GPOINTER_TO_INT(row[COL_PIXVIS]) == FALSE)
1255 			row[COL_BTNVIS] = GINT_TO_POINTER(TRUE);
1256 		if (sym_is_choice(sym))
1257 			break;
1258 	case S_TRISTATE:
1259 		val = sym_get_tristate_value(sym);
1260 		switch (val) {
1261 		case no:
1262 			row[COL_NO] = g_strdup("N");
1263 			row[COL_VALUE] = g_strdup("N");
1264 			row[COL_BTNACT] = GINT_TO_POINTER(FALSE);
1265 			row[COL_BTNINC] = GINT_TO_POINTER(FALSE);
1266 			break;
1267 		case mod:
1268 			row[COL_MOD] = g_strdup("M");
1269 			row[COL_VALUE] = g_strdup("M");
1270 			row[COL_BTNINC] = GINT_TO_POINTER(TRUE);
1271 			break;
1272 		case yes:
1273 			row[COL_YES] = g_strdup("Y");
1274 			row[COL_VALUE] = g_strdup("Y");
1275 			row[COL_BTNACT] = GINT_TO_POINTER(TRUE);
1276 			row[COL_BTNINC] = GINT_TO_POINTER(FALSE);
1277 			break;
1278 		}
1279 
1280 		if (val != no && sym_tristate_within_range(sym, no))
1281 			row[COL_NO] = g_strdup("_");
1282 		if (val != mod && sym_tristate_within_range(sym, mod))
1283 			row[COL_MOD] = g_strdup("_");
1284 		if (val != yes && sym_tristate_within_range(sym, yes))
1285 			row[COL_YES] = g_strdup("_");
1286 		break;
1287 	case S_INT:
1288 	case S_HEX:
1289 	case S_STRING:
1290 		def = sym_get_string_value(sym);
1291 		row[COL_VALUE] = g_strdup(def);
1292 		row[COL_EDIT] = GINT_TO_POINTER(TRUE);
1293 		row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
1294 		break;
1295 	}
1296 
1297 	return row;
1298 }
1299 
1300 
1301 /* Set the node content with a row of strings */
1302 static void set_node(GtkTreeIter * node, struct menu *menu, gchar ** row)
1303 {
1304 	GdkColor color;
1305 	gboolean success;
1306 	GdkPixbuf *pix;
1307 
1308 	pix = gdk_pixbuf_new_from_xpm_data((const char **)
1309 					   row[COL_PIXBUF]);
1310 
1311 	gdk_color_parse(row[COL_COLOR], &color);
1312 	gdk_colormap_alloc_colors(gdk_colormap_get_system(), &color, 1,
1313 				  FALSE, FALSE, &success);
1314 
1315 	gtk_tree_store_set(tree, node,
1316 			   COL_OPTION, row[COL_OPTION],
1317 			   COL_NAME, row[COL_NAME],
1318 			   COL_NO, row[COL_NO],
1319 			   COL_MOD, row[COL_MOD],
1320 			   COL_YES, row[COL_YES],
1321 			   COL_VALUE, row[COL_VALUE],
1322 			   COL_MENU, (gpointer) menu,
1323 			   COL_COLOR, &color,
1324 			   COL_EDIT, GPOINTER_TO_INT(row[COL_EDIT]),
1325 			   COL_PIXBUF, pix,
1326 			   COL_PIXVIS, GPOINTER_TO_INT(row[COL_PIXVIS]),
1327 			   COL_BTNVIS, GPOINTER_TO_INT(row[COL_BTNVIS]),
1328 			   COL_BTNACT, GPOINTER_TO_INT(row[COL_BTNACT]),
1329 			   COL_BTNINC, GPOINTER_TO_INT(row[COL_BTNINC]),
1330 			   COL_BTNRAD, GPOINTER_TO_INT(row[COL_BTNRAD]),
1331 			   -1);
1332 
1333 	g_object_unref(pix);
1334 }
1335 
1336 
1337 /* Add a node to the tree */
1338 static void place_node(struct menu *menu, char **row)
1339 {
1340 	GtkTreeIter *parent = parents[indent - 1];
1341 	GtkTreeIter *node = parents[indent];
1342 
1343 	gtk_tree_store_append(tree, node, parent);
1344 	set_node(node, menu, row);
1345 }
1346 
1347 
1348 /* Find a node in the GTK+ tree */
1349 static GtkTreeIter found;
1350 
1351 /*
1352  * Find a menu in the GtkTree starting at parent.
1353  */
1354 GtkTreeIter *gtktree_iter_find_node(GtkTreeIter * parent,
1355 				    struct menu *tofind)
1356 {
1357 	GtkTreeIter iter;
1358 	GtkTreeIter *child = &iter;
1359 	gboolean valid;
1360 	GtkTreeIter *ret;
1361 
1362 	valid = gtk_tree_model_iter_children(model2, child, parent);
1363 	while (valid) {
1364 		struct menu *menu;
1365 
1366 		gtk_tree_model_get(model2, child, 6, &menu, -1);
1367 
1368 		if (menu == tofind) {
1369 			memcpy(&found, child, sizeof(GtkTreeIter));
1370 			return &found;
1371 		}
1372 
1373 		ret = gtktree_iter_find_node(child, tofind);
1374 		if (ret)
1375 			return ret;
1376 
1377 		valid = gtk_tree_model_iter_next(model2, child);
1378 	}
1379 
1380 	return NULL;
1381 }
1382 
1383 
1384 /*
1385  * Update the tree by adding/removing entries
1386  * Does not change other nodes
1387  */
1388 static void update_tree(struct menu *src, GtkTreeIter * dst)
1389 {
1390 	struct menu *child1;
1391 	GtkTreeIter iter, tmp;
1392 	GtkTreeIter *child2 = &iter;
1393 	gboolean valid;
1394 	GtkTreeIter *sibling;
1395 	struct symbol *sym;
1396 	struct property *prop;
1397 	struct menu *menu1, *menu2;
1398 
1399 	if (src == &rootmenu)
1400 		indent = 1;
1401 
1402 	valid = gtk_tree_model_iter_children(model2, child2, dst);
1403 	for (child1 = src->list; child1; child1 = child1->next) {
1404 
1405 		prop = child1->prompt;
1406 		sym = child1->sym;
1407 
1408 	      reparse:
1409 		menu1 = child1;
1410 		if (valid)
1411 			gtk_tree_model_get(model2, child2, COL_MENU,
1412 					   &menu2, -1);
1413 		else
1414 			menu2 = NULL;	// force adding of a first child
1415 
1416 #ifdef DEBUG
1417 		printf("%*c%s | %s\n", indent, ' ',
1418 		       menu1 ? menu_get_prompt(menu1) : "nil",
1419 		       menu2 ? menu_get_prompt(menu2) : "nil");
1420 #endif
1421 
1422 		if (!menu_is_visible(child1) && !show_all) {	// remove node
1423 			if (gtktree_iter_find_node(dst, menu1) != NULL) {
1424 				memcpy(&tmp, child2, sizeof(GtkTreeIter));
1425 				valid = gtk_tree_model_iter_next(model2,
1426 								 child2);
1427 				gtk_tree_store_remove(tree2, &tmp);
1428 				if (!valid)
1429 					return;	// next parent
1430 				else
1431 					goto reparse;	// next child
1432 			} else
1433 				continue;
1434 		}
1435 
1436 		if (menu1 != menu2) {
1437 			if (gtktree_iter_find_node(dst, menu1) == NULL) {	// add node
1438 				if (!valid && !menu2)
1439 					sibling = NULL;
1440 				else
1441 					sibling = child2;
1442 				gtk_tree_store_insert_before(tree2,
1443 							     child2,
1444 							     dst, sibling);
1445 				set_node(child2, menu1, fill_row(menu1));
1446 				if (menu2 == NULL)
1447 					valid = TRUE;
1448 			} else {	// remove node
1449 				memcpy(&tmp, child2, sizeof(GtkTreeIter));
1450 				valid = gtk_tree_model_iter_next(model2,
1451 								 child2);
1452 				gtk_tree_store_remove(tree2, &tmp);
1453 				if (!valid)
1454 					return;	// next parent
1455 				else
1456 					goto reparse;	// next child
1457 			}
1458 		} else if (sym && (sym->flags & SYMBOL_CHANGED)) {
1459 			set_node(child2, menu1, fill_row(menu1));
1460 		}
1461 
1462 		indent++;
1463 		update_tree(child1, child2);
1464 		indent--;
1465 
1466 		valid = gtk_tree_model_iter_next(model2, child2);
1467 	}
1468 }
1469 
1470 
1471 /* Display the whole tree (single/split/full view) */
1472 static void display_tree(struct menu *menu)
1473 {
1474 	struct symbol *sym;
1475 	struct property *prop;
1476 	struct menu *child;
1477 	enum prop_type ptype;
1478 
1479 	if (menu == &rootmenu) {
1480 		indent = 1;
1481 		current = &rootmenu;
1482 	}
1483 
1484 	for (child = menu->list; child; child = child->next) {
1485 		prop = child->prompt;
1486 		sym = child->sym;
1487 		ptype = prop ? prop->type : P_UNKNOWN;
1488 
1489 		if (sym)
1490 			sym->flags &= ~SYMBOL_CHANGED;
1491 
1492 		if ((view_mode == SPLIT_VIEW)
1493 		    && !(child->flags & MENU_ROOT) && (tree == tree1))
1494 			continue;
1495 
1496 		if ((view_mode == SPLIT_VIEW) && (child->flags & MENU_ROOT)
1497 		    && (tree == tree2))
1498 			continue;
1499 
1500 		if (menu_is_visible(child) || show_all)
1501 			place_node(child, fill_row(child));
1502 #ifdef DEBUG
1503 		printf("%*c%s: ", indent, ' ', menu_get_prompt(child));
1504 		printf("%s", child->flags & MENU_ROOT ? "rootmenu | " : "");
1505 		dbg_print_ptype(ptype);
1506 		printf(" | ");
1507 		if (sym) {
1508 			dbg_print_stype(sym->type);
1509 			printf(" | ");
1510 			dbg_print_flags(sym->flags);
1511 			printf("\n");
1512 		} else
1513 			printf("\n");
1514 #endif
1515 		if ((view_mode != FULL_VIEW) && (ptype == P_MENU)
1516 		    && (tree == tree2))
1517 			continue;
1518 /*
1519                 if (((menu != &rootmenu) && !(menu->flags & MENU_ROOT))
1520 		    || (view_mode == FULL_VIEW)
1521 		    || (view_mode == SPLIT_VIEW))*/
1522 		if (((view_mode == SINGLE_VIEW) && (menu->flags & MENU_ROOT))
1523 		    || (view_mode == FULL_VIEW)
1524 		    || (view_mode == SPLIT_VIEW)) {
1525 			indent++;
1526 			display_tree(child);
1527 			indent--;
1528 		}
1529 	}
1530 }
1531 
1532 /* Display a part of the tree starting at current node (single/split view) */
1533 static void display_tree_part(void)
1534 {
1535 	if (tree2)
1536 		gtk_tree_store_clear(tree2);
1537 	if (view_mode == SINGLE_VIEW)
1538 		display_tree(current);
1539 	else if (view_mode == SPLIT_VIEW)
1540 		display_tree(browsed);
1541 	gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w));
1542 }
1543 
1544 /* Display the list in the left frame (split view) */
1545 static void display_list(void)
1546 {
1547 	if (tree1)
1548 		gtk_tree_store_clear(tree1);
1549 
1550 	tree = tree1;
1551 	display_tree(&rootmenu);
1552 	gtk_tree_view_expand_all(GTK_TREE_VIEW(tree1_w));
1553 	tree = tree2;
1554 }
1555 
1556 void fixup_rootmenu(struct menu *menu)
1557 {
1558 	struct menu *child;
1559 	static int menu_cnt = 0;
1560 
1561 	menu->flags |= MENU_ROOT;
1562 	for (child = menu->list; child; child = child->next) {
1563 		if (child->prompt && child->prompt->type == P_MENU) {
1564 			menu_cnt++;
1565 			fixup_rootmenu(child);
1566 			menu_cnt--;
1567 		} else if (!menu_cnt)
1568 			fixup_rootmenu(child);
1569 	}
1570 }
1571 
1572 
1573 /* Main */
1574 int main(int ac, char *av[])
1575 {
1576 	const char *name;
1577 	char *env;
1578 	gchar *glade_file;
1579 
1580 #ifndef LKC_DIRECT_LINK
1581 	kconfig_load();
1582 #endif
1583 
1584 	bindtextdomain(PACKAGE, LOCALEDIR);
1585 	bind_textdomain_codeset(PACKAGE, "UTF-8");
1586 	textdomain(PACKAGE);
1587 
1588 	/* GTK stuffs */
1589 	gtk_set_locale();
1590 	gtk_init(&ac, &av);
1591 	glade_init();
1592 
1593 	//add_pixmap_directory (PACKAGE_DATA_DIR "/" PACKAGE "/pixmaps");
1594 	//add_pixmap_directory (PACKAGE_SOURCE_DIR "/pixmaps");
1595 
1596 	/* Determine GUI path */
1597 	env = getenv(SRCTREE);
1598 	if (env)
1599 		glade_file = g_strconcat(env, "/scripts/kconfig/gconf.glade", NULL);
1600 	else if (av[0][0] == '/')
1601 		glade_file = g_strconcat(av[0], ".glade", NULL);
1602 	else
1603 		glade_file = g_strconcat(g_get_current_dir(), "/", av[0], ".glade", NULL);
1604 
1605 	/* Load the interface and connect signals */
1606 	init_main_window(glade_file);
1607 	init_tree_model();
1608 	init_left_tree();
1609 	init_right_tree();
1610 
1611 	/* Conf stuffs */
1612 	if (ac > 1 && av[1][0] == '-') {
1613 		switch (av[1][1]) {
1614 		case 'a':
1615 			//showAll = 1;
1616 			break;
1617 		case 'h':
1618 		case '?':
1619 			printf("%s <config>\n", av[0]);
1620 			exit(0);
1621 		}
1622 		name = av[2];
1623 	} else
1624 		name = av[1];
1625 
1626 	conf_parse(name);
1627 	fixup_rootmenu(&rootmenu);
1628 	conf_read(NULL);
1629 
1630 	switch (view_mode) {
1631 	case SINGLE_VIEW:
1632 		display_tree_part();
1633 		break;
1634 	case SPLIT_VIEW:
1635 		display_list();
1636 		break;
1637 	case FULL_VIEW:
1638 		display_tree(&rootmenu);
1639 		break;
1640 	}
1641 
1642 	gtk_main();
1643 
1644 	return 0;
1645 }
1646