xref: /linux/scripts/kconfig/gconf.c (revision 18e2d526bf24525995d4312937e82d9b6810f663)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2002-2003 Romain Lievin <roms@tilp.info>
4  */
5 
6 #include <stdlib.h>
7 #include "lkc.h"
8 
9 #include <gtk/gtk.h>
10 
11 #include <stdio.h>
12 #include <string.h>
13 #include <strings.h>
14 #include <unistd.h>
15 #include <time.h>
16 
17 enum view_mode {
18 	SINGLE_VIEW, SPLIT_VIEW, FULL_VIEW
19 };
20 
21 enum {
22 	OPT_NORMAL, OPT_ALL, OPT_PROMPT
23 };
24 
25 static gint view_mode = FULL_VIEW;
26 static gboolean show_name = TRUE;
27 static gboolean show_range = TRUE;
28 static gboolean show_value = TRUE;
29 static int opt_mode = OPT_NORMAL;
30 
31 static GtkWidget *main_wnd;
32 static GtkWidget *tree1_w;	// left  frame
33 static GtkWidget *tree2_w;	// right frame
34 static GtkWidget *text_w;
35 static GtkWidget *hpaned;
36 static GtkWidget *vpaned;
37 static GtkWidget *back_btn, *save_btn, *single_btn, *split_btn, *full_btn;
38 static GtkWidget *save_menu_item;
39 
40 static GtkTextTag *tag1, *tag2;
41 
42 static GtkTreeStore *tree1, *tree2;
43 static GdkPixbuf *pix_menu;
44 
45 static struct menu *browsed; // browsed menu for SINGLE/SPLIT view
46 static struct menu *selected; // selected entry
47 
48 enum {
49 	COL_OPTION, COL_NAME, COL_NO, COL_MOD, COL_YES, COL_VALUE,
50 	COL_MENU, COL_COLOR, COL_EDIT, COL_PIXBUF,
51 	COL_PIXVIS, COL_BTNVIS, COL_BTNACT, COL_BTNINC, COL_BTNRAD,
52 	COL_NUMBER
53 };
54 
55 static void display_tree(GtkTreeStore *store, struct menu *menu);
56 static void recreate_tree(void);
57 
58 static void conf_changed(bool dirty)
59 {
60 	gtk_widget_set_sensitive(save_btn, dirty);
61 	gtk_widget_set_sensitive(save_menu_item, dirty);
62 }
63 
64 /* Utility Functions */
65 
66 static void text_insert_msg(const char *title, const char *msg)
67 {
68 	GtkTextBuffer *buffer;
69 	GtkTextIter start, end;
70 
71 	buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w));
72 	gtk_text_buffer_get_bounds(buffer, &start, &end);
73 	gtk_text_buffer_delete(buffer, &start, &end);
74 	gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_w), 15);
75 
76 	gtk_text_buffer_get_end_iter(buffer, &end);
77 	gtk_text_buffer_insert_with_tags(buffer, &end, title, -1, tag1,
78 					 NULL);
79 	gtk_text_buffer_insert_at_cursor(buffer, "\n\n", 2);
80 	gtk_text_buffer_get_end_iter(buffer, &end);
81 	gtk_text_buffer_insert_with_tags(buffer, &end, msg, -1, tag2,
82 					 NULL);
83 }
84 
85 static void text_insert_help(struct menu *menu)
86 {
87 	struct gstr help = str_new();
88 
89 	menu_get_ext_help(menu, &help);
90 	text_insert_msg(menu_get_prompt(menu), str_get(&help));
91 	str_free(&help);
92 }
93 
94 static void _select_menu(GtkTreeView *view, GtkTreeModel *model,
95 			 GtkTreeIter *parent, struct menu *match)
96 {
97 	GtkTreeIter iter;
98 	gboolean valid;
99 
100 	valid = gtk_tree_model_iter_children(model, &iter, parent);
101 	while (valid) {
102 		struct menu *menu;
103 
104 		gtk_tree_model_get(model, &iter, COL_MENU, &menu, -1);
105 
106 		if (menu == match) {
107 			GtkTreeSelection *selection;
108 			GtkTreePath *path;
109 
110 			/*
111 			 * Expand parents to reflect the selection, and
112 			 * scroll down to it.
113 			 */
114 			path = gtk_tree_model_get_path(model, &iter);
115 			gtk_tree_view_expand_to_path(view, path);
116 			gtk_tree_view_scroll_to_cell(view, path, NULL, TRUE,
117 						     0.5, 0.0);
118 			gtk_tree_path_free(path);
119 
120 			selection = gtk_tree_view_get_selection(view);
121 			gtk_tree_selection_select_iter(selection, &iter);
122 
123 			text_insert_help(menu);
124 		}
125 
126 		_select_menu(view, model, &iter, match);
127 
128 		valid = gtk_tree_model_iter_next(model, &iter);
129 	}
130 }
131 
132 static void select_menu(GtkTreeView *view, struct menu *match)
133 {
134 	_select_menu(view, gtk_tree_view_get_model(view), NULL, match);
135 }
136 
137 static void _update_row_visibility(GtkTreeView *view)
138 {
139 	GtkTreeModelFilter *filter = GTK_TREE_MODEL_FILTER(gtk_tree_view_get_model(view));
140 
141 	gtk_tree_model_filter_refilter(filter);
142 }
143 
144 static void update_row_visibility(void)
145 {
146 	if (view_mode == SPLIT_VIEW)
147 		_update_row_visibility(GTK_TREE_VIEW(tree1_w));
148 	_update_row_visibility(GTK_TREE_VIEW(tree2_w));
149 }
150 
151 static void set_node(GtkTreeStore *tree, GtkTreeIter *node, struct menu *menu)
152 {
153 	struct symbol *sym = menu->sym;
154 	tristate val;
155 	gchar *option;
156 	const gchar *_no = "";
157 	const gchar *_mod = "";
158 	const gchar *_yes = "";
159 	const gchar *value = "";
160 	GdkRGBA color;
161 	gboolean editable = FALSE;
162 	gboolean btnvis = FALSE;
163 
164 	option = g_strdup_printf("%s %s %s %s",
165 				 menu->type == M_COMMENT ? "***" : "",
166 				 menu_get_prompt(menu),
167 				 menu->type == M_COMMENT ? "***" : "",
168 				 sym && !sym_has_value(sym) ? "(NEW)" : "");
169 
170 	gdk_rgba_parse(&color, menu_is_visible(menu) ? "Black" : "DarkGray");
171 
172 	if (!sym)
173 		goto set;
174 
175 	sym_calc_value(sym);
176 
177 	if (menu->type == M_CHOICE) {	// parse children to get a final value
178 		struct symbol *def_sym = sym_calc_choice(menu);
179 		struct menu *def_menu = NULL;
180 
181 		for (struct menu *child = menu->list; child; child = child->next) {
182 			if (menu_is_visible(child) && child->sym == def_sym)
183 				def_menu = child;
184 		}
185 
186 		if (def_menu)
187 			value = menu_get_prompt(def_menu);
188 
189 		goto set;
190 	}
191 
192 	switch (sym_get_type(sym)) {
193 	case S_BOOLEAN:
194 	case S_TRISTATE:
195 
196 		btnvis = TRUE;
197 
198 		val = sym_get_tristate_value(sym);
199 		switch (val) {
200 		case no:
201 			_no = "N";
202 			value = "N";
203 			break;
204 		case mod:
205 			_mod = "M";
206 			value = "M";
207 			break;
208 		case yes:
209 			_yes = "Y";
210 			value = "Y";
211 			break;
212 		}
213 
214 		if (val != no && sym_tristate_within_range(sym, no))
215 			_no = "_";
216 		if (val != mod && sym_tristate_within_range(sym, mod))
217 			_mod = "_";
218 		if (val != yes && sym_tristate_within_range(sym, yes))
219 			_yes = "_";
220 		break;
221 	default:
222 		value = sym_get_string_value(sym);
223 		editable = TRUE;
224 		break;
225 	}
226 
227 set:
228 	gtk_tree_store_set(tree, node,
229 			   COL_OPTION, option,
230 			   COL_NAME, sym ? sym->name : "",
231 			   COL_NO, _no,
232 			   COL_MOD, _mod,
233 			   COL_YES, _yes,
234 			   COL_VALUE, value,
235 			   COL_MENU, (gpointer) menu,
236 			   COL_COLOR, &color,
237 			   COL_EDIT, editable,
238 			   COL_PIXBUF, pix_menu,
239 			   COL_PIXVIS, view_mode == SINGLE_VIEW && menu->type == M_MENU,
240 			   COL_BTNVIS, btnvis,
241 			   COL_BTNACT, _yes[0] == 'Y',
242 			   COL_BTNINC, _mod[0] == 'M',
243 			   COL_BTNRAD, sym && sym_is_choice_value(sym),
244 			   -1);
245 
246 	g_free(option);
247 }
248 
249 static void _update_tree(GtkTreeStore *store, GtkTreeIter *parent)
250 {
251 	GtkTreeModel *model = GTK_TREE_MODEL(store);
252 	GtkTreeIter iter;
253 	gboolean valid;
254 
255 	valid = gtk_tree_model_iter_children(model, &iter, parent);
256 	while (valid) {
257 		struct menu *menu;
258 
259 		gtk_tree_model_get(model, &iter, COL_MENU, &menu, -1);
260 
261 		if (menu)
262 			set_node(store, &iter, menu);
263 
264 		_update_tree(store, &iter);
265 
266 		valid = gtk_tree_model_iter_next(model, &iter);
267 	}
268 }
269 
270 static void update_tree(GtkTreeStore *store)
271 {
272 	_update_tree(store, NULL);
273 	update_row_visibility();
274 }
275 
276 static void update_trees(void)
277 {
278 	if (view_mode == SPLIT_VIEW)
279 		update_tree(tree1);
280 	update_tree(tree2);
281 }
282 
283 static void set_view_mode(enum view_mode mode)
284 {
285 	view_mode = mode;
286 
287 	if (mode == SPLIT_VIEW) { // two panes
288 		gint w;
289 
290 		gtk_widget_show(tree1_w);
291 		gtk_window_get_default_size(GTK_WINDOW(main_wnd), &w, NULL);
292 		gtk_paned_set_position(GTK_PANED(hpaned), w / 2);
293 	} else {
294 		gtk_widget_hide(tree1_w);
295 		gtk_paned_set_position(GTK_PANED(hpaned), 0);
296 	}
297 
298 	gtk_widget_set_sensitive(single_btn, TRUE);
299 	gtk_widget_set_sensitive(split_btn, TRUE);
300 	gtk_widget_set_sensitive(full_btn, TRUE);
301 
302 	switch (mode) {
303 	case SINGLE_VIEW:
304 		if (selected)
305 			browsed = menu_get_parent_menu(selected) ?: &rootmenu;
306 		else
307 			browsed = &rootmenu;
308 		recreate_tree();
309 		text_insert_msg("", "");
310 		select_menu(GTK_TREE_VIEW(tree2_w), selected);
311 		gtk_widget_set_sensitive(single_btn, FALSE);
312 		break;
313 	case SPLIT_VIEW:
314 		browsed = selected;
315 		while (browsed && !(browsed->flags & MENU_ROOT))
316 			browsed = browsed->parent;
317 		gtk_tree_store_clear(tree1);
318 		display_tree(tree1, &rootmenu);
319 		gtk_tree_view_expand_all(GTK_TREE_VIEW(tree1_w));
320 		gtk_tree_store_clear(tree2);
321 		if (browsed)
322 			display_tree(tree2, browsed);
323 		text_insert_msg("", "");
324 		select_menu(GTK_TREE_VIEW(tree1_w), browsed);
325 		select_menu(GTK_TREE_VIEW(tree2_w), selected);
326 		gtk_widget_set_sensitive(split_btn, FALSE);
327 		break;
328 	case FULL_VIEW:
329 		gtk_tree_store_clear(tree2);
330 		display_tree(tree2, &rootmenu);
331 		text_insert_msg("", "");
332 		select_menu(GTK_TREE_VIEW(tree2_w), selected);
333 		gtk_widget_set_sensitive(full_btn, FALSE);
334 		break;
335 	}
336 
337 	gtk_widget_set_sensitive(back_btn,
338 				 mode == SINGLE_VIEW && browsed != &rootmenu);
339 }
340 
341 /* Menu & Toolbar Callbacks */
342 
343 static void on_load1_activate(GtkMenuItem *menuitem, gpointer user_data)
344 {
345 	GtkWidget *dialog;
346 	GtkFileChooser *chooser;
347 	gint res;
348 
349 	dialog = gtk_file_chooser_dialog_new("Load file...",
350 					     GTK_WINDOW(user_data),
351 					     GTK_FILE_CHOOSER_ACTION_OPEN,
352 					     "_Cancel", GTK_RESPONSE_CANCEL,
353 					     "_Open", GTK_RESPONSE_ACCEPT,
354 					     NULL);
355 
356 	chooser = GTK_FILE_CHOOSER(dialog);
357 	gtk_file_chooser_set_filename(chooser, conf_get_configname());
358 
359 	res = gtk_dialog_run(GTK_DIALOG(dialog));
360 	if (res == GTK_RESPONSE_ACCEPT) {
361 		char *filename;
362 
363 		filename = gtk_file_chooser_get_filename(chooser);
364 
365 		if (conf_read(filename))
366 			text_insert_msg("Error",
367 					"Unable to load configuration!");
368 		else
369 			update_trees();
370 
371 		g_free(filename);
372 	}
373 
374 	gtk_widget_destroy(GTK_WIDGET(dialog));
375 }
376 
377 static void on_save_activate(GtkMenuItem *menuitem, gpointer user_data)
378 {
379 	if (conf_write(NULL))
380 		text_insert_msg("Error", "Unable to save configuration !");
381 	conf_write_autoconf(0);
382 }
383 
384 static void on_save_as1_activate(GtkMenuItem *menuitem, gpointer user_data)
385 {
386 	GtkWidget *dialog;
387 	GtkFileChooser *chooser;
388 	gint res;
389 
390 	dialog = gtk_file_chooser_dialog_new("Save file as...",
391 					     GTK_WINDOW(user_data),
392 					     GTK_FILE_CHOOSER_ACTION_SAVE,
393 					     "_Cancel", GTK_RESPONSE_CANCEL,
394 					     "_Save", GTK_RESPONSE_ACCEPT,
395 					     NULL);
396 
397 	chooser = GTK_FILE_CHOOSER(dialog);
398 	gtk_file_chooser_set_filename(chooser, conf_get_configname());
399 
400 	res = gtk_dialog_run(GTK_DIALOG(dialog));
401 	if (res == GTK_RESPONSE_ACCEPT) {
402 		char *filename;
403 
404 		filename = gtk_file_chooser_get_filename(chooser);
405 
406 		if (conf_write(filename))
407 			text_insert_msg("Error",
408 					"Unable to save configuration !");
409 
410 		g_free(filename);
411 	}
412 
413 	gtk_widget_destroy(dialog);
414 }
415 
416 static void on_show_name1_activate(GtkMenuItem *menuitem, gpointer user_data)
417 {
418 	GtkTreeViewColumn *col;
419 
420 	show_name = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menuitem));
421 	col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_NAME);
422 	if (col)
423 		gtk_tree_view_column_set_visible(col, show_name);
424 }
425 
426 static void on_show_range1_activate(GtkMenuItem *menuitem, gpointer user_data)
427 {
428 	GtkTreeViewColumn *col;
429 
430 	show_range = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menuitem));
431 	col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_NO);
432 	if (col)
433 		gtk_tree_view_column_set_visible(col, show_range);
434 	col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_MOD);
435 	if (col)
436 		gtk_tree_view_column_set_visible(col, show_range);
437 	col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_YES);
438 	if (col)
439 		gtk_tree_view_column_set_visible(col, show_range);
440 
441 }
442 
443 static void on_show_data1_activate(GtkMenuItem *menuitem, gpointer user_data)
444 {
445 	GtkTreeViewColumn *col;
446 
447 	show_value = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menuitem));
448 	col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_VALUE);
449 	if (col)
450 		gtk_tree_view_column_set_visible(col, show_value);
451 }
452 
453 static void on_set_option_mode1_activate(GtkMenuItem *menuitem,
454 					 gpointer user_data)
455 {
456 	opt_mode = OPT_NORMAL;
457 	update_row_visibility();
458 }
459 
460 static void on_set_option_mode2_activate(GtkMenuItem *menuitem,
461 					 gpointer user_data)
462 {
463 	opt_mode = OPT_ALL;
464 	update_row_visibility();
465 }
466 
467 static void on_set_option_mode3_activate(GtkMenuItem *menuitem,
468 					 gpointer user_data)
469 {
470 	opt_mode = OPT_PROMPT;
471 	update_row_visibility();
472 }
473 
474 static void on_introduction1_activate(GtkMenuItem *menuitem, gpointer user_data)
475 {
476 	GtkWidget *dialog;
477 	const gchar *intro_text =
478 	    "Welcome to gconfig, the GTK+ graphical configuration tool.\n"
479 	    "For each option, a blank box indicates the feature is disabled, a\n"
480 	    "check indicates it is enabled, and a dot indicates that it is to\n"
481 	    "be compiled as a module.  Clicking on the box will cycle through the three states.\n"
482 	    "\n"
483 	    "If you do not see an option (e.g., a device driver) that you\n"
484 	    "believe should be present, try turning on Show All Options\n"
485 	    "under the Options menu.\n"
486 	    "Although there is no cross reference yet to help you figure out\n"
487 	    "what other options must be enabled to support the option you\n"
488 	    "are interested in, you can still view the help of a grayed-out\n"
489 	    "option.";
490 
491 	dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
492 					GTK_DIALOG_DESTROY_WITH_PARENT,
493 					GTK_MESSAGE_INFO,
494 					GTK_BUTTONS_CLOSE, "%s", intro_text);
495 	gtk_dialog_run(GTK_DIALOG(dialog));
496 	gtk_widget_destroy(dialog);
497 }
498 
499 static void on_about1_activate(GtkMenuItem *menuitem, gpointer user_data)
500 {
501 	GtkWidget *dialog;
502 	const gchar *about_text =
503 	    "gconfig is copyright (c) 2002 Romain Lievin <roms@lpg.ticalc.org>.\n"
504 	      "Based on the source code from Roman Zippel.\n";
505 
506 	dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
507 					GTK_DIALOG_DESTROY_WITH_PARENT,
508 					GTK_MESSAGE_INFO,
509 					GTK_BUTTONS_CLOSE, "%s\nGTK version: %d.%d.%d",
510 					about_text,
511 					gtk_get_major_version(),
512 					gtk_get_minor_version(),
513 					gtk_get_micro_version());
514 	gtk_dialog_run(GTK_DIALOG(dialog));
515 	gtk_widget_destroy(dialog);
516 }
517 
518 static void on_license1_activate(GtkMenuItem *menuitem, gpointer user_data)
519 {
520 	GtkWidget *dialog;
521 	const gchar *license_text =
522 	    "gconfig is released under the terms of the GNU GPL v2.\n"
523 	      "For more information, please see the source code or\n"
524 	      "visit http://www.fsf.org/licenses/licenses.html\n";
525 
526 	dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
527 					GTK_DIALOG_DESTROY_WITH_PARENT,
528 					GTK_MESSAGE_INFO,
529 					GTK_BUTTONS_CLOSE, "%s", license_text);
530 	gtk_dialog_run(GTK_DIALOG(dialog));
531 	gtk_widget_destroy(dialog);
532 }
533 
534 /* toolbar handlers */
535 static void on_back_clicked(GtkButton *button, gpointer user_data)
536 {
537 	browsed = menu_get_parent_menu(browsed) ?: &rootmenu;
538 
539 	recreate_tree();
540 
541 	if (browsed == &rootmenu)
542 		gtk_widget_set_sensitive(back_btn, FALSE);
543 }
544 
545 static void on_load_clicked(GtkButton *button, gpointer user_data)
546 {
547 	on_load1_activate(NULL, user_data);
548 }
549 
550 static void on_save_clicked(GtkButton *button, gpointer user_data)
551 {
552 	on_save_activate(NULL, user_data);
553 }
554 
555 static void on_single_clicked(GtkButton *button, gpointer user_data)
556 {
557 	set_view_mode(SINGLE_VIEW);
558 }
559 
560 static void on_split_clicked(GtkButton *button, gpointer user_data)
561 {
562 	set_view_mode(SPLIT_VIEW);
563 }
564 
565 static void on_full_clicked(GtkButton *button, gpointer user_data)
566 {
567 	set_view_mode(FULL_VIEW);
568 }
569 
570 static void on_collapse_clicked(GtkButton *button, gpointer user_data)
571 {
572 	gtk_tree_view_collapse_all(GTK_TREE_VIEW(tree2_w));
573 }
574 
575 static void on_expand_clicked(GtkButton *button, gpointer user_data)
576 {
577 	gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w));
578 }
579 
580 /* Main Windows Callbacks */
581 
582 static void on_window1_destroy(GtkWidget *widget, gpointer user_data)
583 {
584 	gtk_main_quit();
585 }
586 
587 static gboolean on_window1_configure(GtkWidget *self,
588 				     GdkEventConfigure *event,
589 				     gpointer user_data)
590 {
591 	gtk_paned_set_position(GTK_PANED(vpaned), 2 * event->height / 3);
592 	return FALSE;
593 }
594 
595 static gboolean on_window1_delete_event(GtkWidget *widget, GdkEvent *event,
596 					gpointer user_data)
597 {
598 	GtkWidget *dialog, *label, *content_area;
599 	gint result;
600 	gint ret = FALSE;
601 
602 	if (!conf_get_changed())
603 		return FALSE;
604 
605 	dialog = gtk_dialog_new_with_buttons("Warning !",
606 					     GTK_WINDOW(main_wnd),
607 					     (GtkDialogFlags)
608 					     (GTK_DIALOG_MODAL |
609 					      GTK_DIALOG_DESTROY_WITH_PARENT),
610 					     "_OK",
611 					     GTK_RESPONSE_YES,
612 					     "_No",
613 					     GTK_RESPONSE_NO,
614 					     "_Cancel",
615 					     GTK_RESPONSE_CANCEL, NULL);
616 	gtk_dialog_set_default_response(GTK_DIALOG(dialog),
617 					GTK_RESPONSE_CANCEL);
618 
619 	label = gtk_label_new("\nSave configuration ?\n");
620 	content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
621 	gtk_container_add(GTK_CONTAINER(content_area), label);
622 	gtk_widget_show(label);
623 
624 	result = gtk_dialog_run(GTK_DIALOG(dialog));
625 	switch (result) {
626 	case GTK_RESPONSE_YES:
627 		on_save_activate(NULL, NULL);
628 		break;
629 	case GTK_RESPONSE_NO:
630 		break;
631 	case GTK_RESPONSE_CANCEL:
632 	case GTK_RESPONSE_DELETE_EVENT:
633 	default:
634 		ret = TRUE;
635 		break;
636 	}
637 
638 	gtk_widget_destroy(dialog);
639 
640 	if (!ret)
641 		g_object_unref(pix_menu);
642 
643 	return ret;
644 }
645 
646 static void on_quit1_activate(GtkMenuItem *menuitem, gpointer user_data)
647 {
648 	if (!on_window1_delete_event(NULL, NULL, NULL))
649 		gtk_widget_destroy(GTK_WIDGET(main_wnd));
650 }
651 
652 /* CTree Callbacks */
653 
654 /* Change hex/int/string value in the cell */
655 static void renderer_edited(GtkCellRendererText * cell,
656 			    const gchar * path_string,
657 			    const gchar * new_text, gpointer user_data)
658 {
659 	GtkTreeView *view = GTK_TREE_VIEW(user_data);
660 	GtkTreeModel *model = gtk_tree_view_get_model(view);
661 	GtkTreePath *path = gtk_tree_path_new_from_string(path_string);
662 	GtkTreeIter iter;
663 	const char *old_def, *new_def;
664 	struct menu *menu;
665 	struct symbol *sym;
666 
667 	if (!gtk_tree_model_get_iter(model, &iter, path))
668 		goto free;
669 
670 	gtk_tree_model_get(model, &iter, COL_MENU, &menu, -1);
671 	sym = menu->sym;
672 
673 	gtk_tree_model_get(model, &iter, COL_VALUE, &old_def, -1);
674 	new_def = new_text;
675 
676 	sym_set_string_value(sym, new_def);
677 
678 	update_trees();
679 
680 free:
681 	gtk_tree_path_free(path);
682 }
683 
684 /* Change the value of a symbol and update the tree */
685 static void change_sym_value(struct menu *menu, gint col)
686 {
687 	struct symbol *sym = menu->sym;
688 	tristate newval;
689 
690 	if (!sym)
691 		return;
692 
693 	if (col == COL_NO)
694 		newval = no;
695 	else if (col == COL_MOD)
696 		newval = mod;
697 	else if (col == COL_YES)
698 		newval = yes;
699 	else
700 		return;
701 
702 	switch (sym_get_type(sym)) {
703 	case S_BOOLEAN:
704 	case S_TRISTATE:
705 		if (!sym_tristate_within_range(sym, newval))
706 			newval = yes;
707 		sym_set_tristate_value(sym, newval);
708 		update_trees();
709 		break;
710 	case S_INT:
711 	case S_HEX:
712 	case S_STRING:
713 	default:
714 		break;
715 	}
716 }
717 
718 static void toggle_sym_value(struct menu *menu)
719 {
720 	if (!menu->sym)
721 		return;
722 
723 	sym_toggle_tristate_value(menu->sym);
724 	update_trees();
725 }
726 
727 static gint column2index(GtkTreeViewColumn * column)
728 {
729 	gint i;
730 
731 	for (i = 0; i < COL_NUMBER; i++) {
732 		GtkTreeViewColumn *col;
733 
734 		col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), i);
735 		if (col == column)
736 			return i;
737 	}
738 
739 	return -1;
740 }
741 
742 
743 /* User click: update choice (full) or goes down (single) */
744 static gboolean on_treeview2_button_press_event(GtkWidget *widget,
745 						GdkEventButton *event,
746 						gpointer user_data)
747 {
748 	GtkTreeView *view = GTK_TREE_VIEW(widget);
749 	GtkTreeModel *model = gtk_tree_view_get_model(view);
750 	GtkTreePath *path;
751 	GtkTreeViewColumn *column;
752 	GtkTreeIter iter;
753 	struct menu *menu;
754 	gint col;
755 	gint tx = (gint) event->x;
756 	gint ty = (gint) event->y;
757 
758 	gtk_tree_view_get_path_at_pos(view, tx, ty, &path, &column, NULL, NULL);
759 	if (path == NULL)
760 		return FALSE;
761 
762 	if (!gtk_tree_model_get_iter(model, &iter, path))
763 		return FALSE;
764 	gtk_tree_model_get(model, &iter, COL_MENU, &menu, -1);
765 
766 	selected = menu;
767 
768 	col = column2index(column);
769 	if (event->type == GDK_2BUTTON_PRESS) {
770 		enum prop_type ptype;
771 		ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
772 
773 		if (ptype == P_MENU && view_mode == SINGLE_VIEW && col == COL_OPTION) {
774 			// goes down into menu
775 			browsed = menu;
776 			recreate_tree();
777 			gtk_widget_set_sensitive(back_btn, TRUE);
778 		} else if (col == COL_OPTION) {
779 			toggle_sym_value(menu);
780 			gtk_tree_view_expand_row(view, path, TRUE);
781 		}
782 	} else {
783 		if (col == COL_VALUE) {
784 			toggle_sym_value(menu);
785 			gtk_tree_view_expand_row(view, path, TRUE);
786 		} else if (col == COL_NO || col == COL_MOD
787 			   || col == COL_YES) {
788 			change_sym_value(menu, col);
789 			gtk_tree_view_expand_row(view, path, TRUE);
790 		}
791 	}
792 
793 	return FALSE;
794 }
795 
796 /* Key pressed: update choice */
797 static gboolean on_treeview2_key_press_event(GtkWidget *widget,
798 					     GdkEventKey *event,
799 					     gpointer user_data)
800 {
801 	GtkTreeView *view = GTK_TREE_VIEW(widget);
802 	GtkTreeModel *model = gtk_tree_view_get_model(view);
803 	GtkTreePath *path;
804 	GtkTreeIter iter;
805 	struct menu *menu;
806 	gint col;
807 
808 	gtk_tree_view_get_cursor(view, &path, NULL);
809 	if (path == NULL)
810 		return FALSE;
811 
812 	if (event->keyval == GDK_KEY_space) {
813 		if (gtk_tree_view_row_expanded(view, path))
814 			gtk_tree_view_collapse_row(view, path);
815 		else
816 			gtk_tree_view_expand_row(view, path, FALSE);
817 		return TRUE;
818 	}
819 
820 	gtk_tree_model_get_iter(model, &iter, path);
821 	gtk_tree_model_get(model, &iter, COL_MENU, &menu, -1);
822 
823 	if (!strcasecmp(event->string, "n"))
824 		col = COL_NO;
825 	else if (!strcasecmp(event->string, "m"))
826 		col = COL_MOD;
827 	else if (!strcasecmp(event->string, "y"))
828 		col = COL_YES;
829 	else
830 		col = -1;
831 	change_sym_value(menu, col);
832 
833 	return FALSE;
834 }
835 
836 
837 /* Row selection changed: update help */
838 static void on_treeview2_cursor_changed(GtkTreeView *treeview,
839 					gpointer user_data)
840 {
841 	GtkTreeModel *model = gtk_tree_view_get_model(treeview);
842 	GtkTreeSelection *selection;
843 	GtkTreeIter iter;
844 	struct menu *menu;
845 
846 	selection = gtk_tree_view_get_selection(treeview);
847 	if (gtk_tree_selection_get_selected(selection, &model, &iter)) {
848 		gtk_tree_model_get(model, &iter, COL_MENU, &menu, -1);
849 		text_insert_help(menu);
850 	}
851 }
852 
853 
854 /* User click: display sub-tree in the right frame. */
855 static gboolean on_treeview1_button_press_event(GtkWidget *widget,
856 						GdkEventButton *event,
857 						gpointer user_data)
858 {
859 	GtkTreeView *view = GTK_TREE_VIEW(widget);
860 	GtkTreeModel *model = gtk_tree_view_get_model(view);
861 	GtkTreePath *path;
862 	GtkTreeIter iter;
863 	struct menu *menu;
864 	gint tx = (gint) event->x;
865 	gint ty = (gint) event->y;
866 
867 	gtk_tree_view_get_path_at_pos(view, tx, ty, &path, NULL, NULL, NULL);
868 	if (path == NULL)
869 		return FALSE;
870 
871 	gtk_tree_model_get_iter(model, &iter, path);
872 	gtk_tree_model_get(model, &iter, COL_MENU, &menu, -1);
873 
874 	if (event->type == GDK_2BUTTON_PRESS)
875 		toggle_sym_value(menu);
876 
877 	selected = menu;
878 
879 	if (menu->type == M_MENU) {
880 		browsed = menu;
881 		recreate_tree();
882 	}
883 
884 	gtk_tree_view_set_cursor(view, path, NULL, FALSE);
885 	gtk_widget_grab_focus(tree2_w);
886 
887 	return FALSE;
888 }
889 
890 /* Display the whole tree (single/split/full view) */
891 static void _display_tree(GtkTreeStore *tree, struct menu *menu,
892 			  GtkTreeIter *parent)
893 {
894 	struct menu *child;
895 	GtkTreeIter iter;
896 
897 	for (child = menu->list; child; child = child->next) {
898 		/*
899 		 * REVISIT:
900 		 * menu_finalize() creates empty "if" entries.
901 		 * Do not confuse gtk_tree_model_get(), which would otherwise
902 		 * return "if" menu entry.
903 		 */
904 		if (child->type == M_IF)
905 			continue;
906 
907 		if ((view_mode == SPLIT_VIEW)
908 		    && !(child->flags & MENU_ROOT) && (tree == tree1))
909 			continue;
910 
911 		if ((view_mode == SPLIT_VIEW) && (child->flags & MENU_ROOT)
912 		    && (tree == tree2))
913 			continue;
914 
915 		gtk_tree_store_append(tree, &iter, parent);
916 		set_node(tree, &iter, child);
917 
918 		if (view_mode != SINGLE_VIEW || child->type != M_MENU)
919 			_display_tree(tree, child, &iter);
920 	}
921 }
922 
923 static void display_tree(GtkTreeStore *store, struct menu *menu)
924 {
925 	_display_tree(store, menu, NULL);
926 }
927 
928 /* Recreate the tree store starting at 'browsed' node */
929 static void recreate_tree(void)
930 {
931 	gtk_tree_store_clear(tree2);
932 	display_tree(tree2, browsed);
933 	gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w));
934 }
935 
936 static void fixup_rootmenu(struct menu *menu)
937 {
938 	struct menu *child;
939 	static int menu_cnt = 0;
940 
941 	menu->flags |= MENU_ROOT;
942 	for (child = menu->list; child; child = child->next) {
943 		if (child->prompt && child->prompt->type == P_MENU) {
944 			menu_cnt++;
945 			fixup_rootmenu(child);
946 			menu_cnt--;
947 		} else if (!menu_cnt)
948 			fixup_rootmenu(child);
949 	}
950 }
951 
952 /* Main Window Initialization */
953 static void replace_button_icon(GtkWidget *widget, const char *filename)
954 {
955 	GdkPixbuf *pixbuf;
956 	GtkWidget *image;
957 	GError *err = NULL;
958 
959 	char *env = getenv(SRCTREE);
960 	gchar *path = g_strconcat(env ? env : g_get_current_dir(), "/scripts/kconfig/icons/", filename, NULL);
961 
962 	pixbuf = gdk_pixbuf_new_from_file(path, &err);
963 	g_free(path);
964 
965 	if (err) {
966 		g_warning("Failed to load icon %s: %s", filename, err->message);
967 		g_error_free(err);
968 		return;
969 	}
970 
971 	image = gtk_image_new_from_pixbuf(pixbuf);
972 	g_object_unref(pixbuf);
973 
974 	gtk_widget_show(image);
975 	gtk_tool_button_set_icon_widget(GTK_TOOL_BUTTON(widget), image);
976 }
977 
978 static void init_main_window(const gchar *glade_file)
979 {
980 	GtkBuilder *builder;
981 	GtkWidget *widget;
982 	GtkTextBuffer *txtbuf;
983 
984 	builder = gtk_builder_new_from_file(glade_file);
985 	if (!builder)
986 		g_error("GUI loading failed !\n");
987 
988 	main_wnd = GTK_WIDGET(gtk_builder_get_object(builder, "window1"));
989 	g_signal_connect(main_wnd, "destroy",
990 			 G_CALLBACK(on_window1_destroy), NULL);
991 	g_signal_connect(main_wnd, "configure-event",
992 			 G_CALLBACK(on_window1_configure), NULL);
993 	g_signal_connect(main_wnd, "delete-event",
994 			 G_CALLBACK(on_window1_delete_event), NULL);
995 
996 	hpaned = GTK_WIDGET(gtk_builder_get_object(builder, "hpaned1"));
997 	vpaned = GTK_WIDGET(gtk_builder_get_object(builder, "vpaned1"));
998 	tree1_w = GTK_WIDGET(gtk_builder_get_object(builder, "treeview1"));
999 	g_signal_connect(tree1_w, "cursor-changed",
1000 			 G_CALLBACK(on_treeview2_cursor_changed), NULL);
1001 	g_signal_connect(tree1_w, "button-press-event",
1002 			 G_CALLBACK(on_treeview1_button_press_event), NULL);
1003 	g_signal_connect(tree1_w, "key-press-event",
1004 			 G_CALLBACK(on_treeview2_key_press_event), NULL);
1005 
1006 	tree2_w = GTK_WIDGET(gtk_builder_get_object(builder, "treeview2"));
1007 	g_signal_connect(tree2_w, "cursor-changed",
1008 			 G_CALLBACK(on_treeview2_cursor_changed), NULL);
1009 	g_signal_connect(tree2_w, "button-press-event",
1010 			 G_CALLBACK(on_treeview2_button_press_event), NULL);
1011 	g_signal_connect(tree2_w, "key-press-event",
1012 			 G_CALLBACK(on_treeview2_key_press_event), NULL);
1013 
1014 	text_w = GTK_WIDGET(gtk_builder_get_object(builder, "textview3"));
1015 
1016 	/* menubar */
1017 	widget = GTK_WIDGET(gtk_builder_get_object(builder, "load1"));
1018 	g_signal_connect(widget, "activate",
1019 			 G_CALLBACK(on_load1_activate), NULL);
1020 
1021 	save_menu_item = GTK_WIDGET(gtk_builder_get_object(builder, "save1"));
1022 	g_signal_connect(save_menu_item, "activate",
1023 			 G_CALLBACK(on_save_activate), NULL);
1024 
1025 	widget = GTK_WIDGET(gtk_builder_get_object(builder, "save_as1"));
1026 	g_signal_connect(widget, "activate",
1027 			 G_CALLBACK(on_save_as1_activate), NULL);
1028 
1029 	widget = GTK_WIDGET(gtk_builder_get_object(builder, "quit1"));
1030 	g_signal_connect(widget, "activate",
1031 			 G_CALLBACK(on_quit1_activate), NULL);
1032 
1033 	widget = GTK_WIDGET(gtk_builder_get_object(builder, "show_name1"));
1034 	g_signal_connect(widget, "activate",
1035 			 G_CALLBACK(on_show_name1_activate), NULL);
1036 	gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget,
1037 				       show_name);
1038 
1039 	widget = GTK_WIDGET(gtk_builder_get_object(builder, "show_range1"));
1040 	g_signal_connect(widget, "activate",
1041 			 G_CALLBACK(on_show_range1_activate), NULL);
1042 	gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget,
1043 				       show_range);
1044 
1045 	widget = GTK_WIDGET(gtk_builder_get_object(builder, "show_data1"));
1046 	g_signal_connect(widget, "activate",
1047 			 G_CALLBACK(on_show_data1_activate), NULL);
1048 	gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget,
1049 				       show_value);
1050 
1051 	widget = GTK_WIDGET(gtk_builder_get_object(builder, "set_option_mode1"));
1052 	g_signal_connect(widget, "activate",
1053 			 G_CALLBACK(on_set_option_mode1_activate), NULL);
1054 
1055 	widget = GTK_WIDGET(gtk_builder_get_object(builder, "set_option_mode2"));
1056 	g_signal_connect(widget, "activate",
1057 			 G_CALLBACK(on_set_option_mode2_activate), NULL);
1058 
1059 	widget = GTK_WIDGET(gtk_builder_get_object(builder, "set_option_mode3"));
1060 	g_signal_connect(widget, "activate",
1061 			 G_CALLBACK(on_set_option_mode3_activate), NULL);
1062 
1063 	widget = GTK_WIDGET(gtk_builder_get_object(builder, "introduction1"));
1064 	g_signal_connect(widget, "activate",
1065 			 G_CALLBACK(on_introduction1_activate), NULL);
1066 
1067 	widget = GTK_WIDGET(gtk_builder_get_object(builder, "about1"));
1068 	g_signal_connect(widget, "activate",
1069 			 G_CALLBACK(on_about1_activate), NULL);
1070 
1071 	widget = GTK_WIDGET(gtk_builder_get_object(builder, "license1"));
1072 	g_signal_connect(widget, "activate",
1073 			 G_CALLBACK(on_license1_activate), NULL);
1074 
1075 	/* toolbar */
1076 	back_btn = GTK_WIDGET(gtk_builder_get_object(builder, "button1"));
1077 	g_signal_connect(back_btn, "clicked",
1078 			 G_CALLBACK(on_back_clicked), NULL);
1079 	gtk_widget_set_sensitive(back_btn, FALSE);
1080 
1081 	widget = GTK_WIDGET(gtk_builder_get_object(builder, "button2"));
1082 	g_signal_connect(widget, "clicked",
1083 			 G_CALLBACK(on_load_clicked), NULL);
1084 
1085 	save_btn = GTK_WIDGET(gtk_builder_get_object(builder, "button3"));
1086 	g_signal_connect(save_btn, "clicked",
1087 			 G_CALLBACK(on_save_clicked), NULL);
1088 
1089 	single_btn = GTK_WIDGET(gtk_builder_get_object(builder, "button4"));
1090 	g_signal_connect(single_btn, "clicked",
1091 			 G_CALLBACK(on_single_clicked), NULL);
1092 	replace_button_icon(single_btn, "single_view.xpm");
1093 
1094 	split_btn = GTK_WIDGET(gtk_builder_get_object(builder, "button5"));
1095 	g_signal_connect(split_btn, "clicked",
1096 			 G_CALLBACK(on_split_clicked), NULL);
1097 	replace_button_icon(split_btn, "split_view.xpm");
1098 
1099 	full_btn = GTK_WIDGET(gtk_builder_get_object(builder, "button6"));
1100 	g_signal_connect(full_btn, "clicked",
1101 			 G_CALLBACK(on_full_clicked), NULL);
1102 	replace_button_icon(full_btn, "tree_view.xpm");
1103 
1104 	widget = GTK_WIDGET(gtk_builder_get_object(builder, "button7"));
1105 	g_signal_connect(widget, "clicked",
1106 			 G_CALLBACK(on_collapse_clicked), NULL);
1107 
1108 	widget = GTK_WIDGET(gtk_builder_get_object(builder, "button8"));
1109 	g_signal_connect(widget, "clicked",
1110 			 G_CALLBACK(on_expand_clicked), NULL);
1111 
1112 	txtbuf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w));
1113 	tag1 = gtk_text_buffer_create_tag(txtbuf, "mytag1",
1114 					  "foreground", "red",
1115 					  "weight", PANGO_WEIGHT_BOLD,
1116 					  NULL);
1117 	tag2 = gtk_text_buffer_create_tag(txtbuf, "mytag2",
1118 					  /*"style", PANGO_STYLE_OBLIQUE, */
1119 					  NULL);
1120 
1121 	gtk_window_set_title(GTK_WINDOW(main_wnd), rootmenu.prompt->text);
1122 
1123 	gtk_widget_show_all(main_wnd);
1124 
1125 	g_object_unref(builder);
1126 
1127 	conf_set_changed_callback(conf_changed);
1128 }
1129 
1130 static gboolean visible_func(GtkTreeModel *model, GtkTreeIter  *iter,
1131 			     gpointer data)
1132 {
1133 	struct menu *menu;
1134 
1135 	gtk_tree_model_get(model, iter, COL_MENU, &menu, -1);
1136 
1137 	if (!menu)
1138 		return FALSE;
1139 
1140 	return menu_is_visible(menu) || opt_mode == OPT_ALL ||
1141 		(opt_mode == OPT_PROMPT && menu_has_prompt(menu));
1142 }
1143 
1144 static void init_left_tree(void)
1145 {
1146 	GtkTreeView *view = GTK_TREE_VIEW(tree1_w);
1147 	GtkCellRenderer *renderer;
1148 	GtkTreeSelection *sel;
1149 	GtkTreeViewColumn *column;
1150 	GtkTreeModel *filter;
1151 
1152 	tree1 = gtk_tree_store_new(COL_NUMBER,
1153 				   G_TYPE_STRING, G_TYPE_STRING,
1154 				   G_TYPE_STRING, G_TYPE_STRING,
1155 				   G_TYPE_STRING, G_TYPE_STRING,
1156 				   G_TYPE_POINTER, GDK_TYPE_RGBA,
1157 				   G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF,
1158 				   G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
1159 				   G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
1160 				   G_TYPE_BOOLEAN);
1161 
1162 	filter = gtk_tree_model_filter_new(GTK_TREE_MODEL(tree1), NULL);
1163 
1164 	gtk_tree_model_filter_set_visible_func(GTK_TREE_MODEL_FILTER(filter),
1165 					       visible_func, NULL, NULL);
1166 	gtk_tree_view_set_model(view, filter);
1167 
1168 	column = gtk_tree_view_column_new();
1169 	gtk_tree_view_append_column(view, column);
1170 	gtk_tree_view_column_set_title(column, "Options");
1171 
1172 	renderer = gtk_cell_renderer_toggle_new();
1173 	gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
1174 					renderer, FALSE);
1175 	gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
1176 					    renderer,
1177 					    "active", COL_BTNACT,
1178 					    "inconsistent", COL_BTNINC,
1179 					    "visible", COL_BTNVIS,
1180 					    "radio", COL_BTNRAD, NULL);
1181 	renderer = gtk_cell_renderer_text_new();
1182 	gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
1183 					renderer, FALSE);
1184 	gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
1185 					    renderer,
1186 					    "text", COL_OPTION,
1187 					    "foreground-rgba",
1188 					    COL_COLOR, NULL);
1189 
1190 	sel = gtk_tree_view_get_selection(view);
1191 	gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
1192 }
1193 
1194 static void init_right_tree(void)
1195 {
1196 	GtkTreeView *view = GTK_TREE_VIEW(tree2_w);
1197 	GtkCellRenderer *renderer;
1198 	GtkTreeSelection *sel;
1199 	GtkTreeViewColumn *column;
1200 	GtkTreeModel *filter;
1201 	gint i;
1202 
1203 	tree2 = gtk_tree_store_new(COL_NUMBER,
1204 				   G_TYPE_STRING, G_TYPE_STRING,
1205 				   G_TYPE_STRING, G_TYPE_STRING,
1206 				   G_TYPE_STRING, G_TYPE_STRING,
1207 				   G_TYPE_POINTER, GDK_TYPE_RGBA,
1208 				   G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF,
1209 				   G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
1210 				   G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
1211 				   G_TYPE_BOOLEAN);
1212 
1213 	filter = gtk_tree_model_filter_new(GTK_TREE_MODEL(tree2), NULL);
1214 
1215 	gtk_tree_model_filter_set_visible_func(GTK_TREE_MODEL_FILTER(filter),
1216 					       visible_func, NULL, NULL);
1217 	gtk_tree_view_set_model(view, filter);
1218 
1219 	column = gtk_tree_view_column_new();
1220 	gtk_tree_view_append_column(view, column);
1221 	gtk_tree_view_column_set_title(column, "Options");
1222 
1223 	renderer = gtk_cell_renderer_pixbuf_new();
1224 	gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
1225 					renderer, FALSE);
1226 	gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
1227 					    renderer,
1228 					    "pixbuf", COL_PIXBUF,
1229 					    "visible", COL_PIXVIS, NULL);
1230 	renderer = gtk_cell_renderer_toggle_new();
1231 	gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
1232 					renderer, FALSE);
1233 	gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
1234 					    renderer,
1235 					    "active", COL_BTNACT,
1236 					    "inconsistent", COL_BTNINC,
1237 					    "visible", COL_BTNVIS,
1238 					    "radio", COL_BTNRAD, NULL);
1239 	renderer = gtk_cell_renderer_text_new();
1240 	gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
1241 					renderer, FALSE);
1242 	gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
1243 					    renderer,
1244 					    "text", COL_OPTION,
1245 					    "foreground-rgba",
1246 					    COL_COLOR, NULL);
1247 
1248 	renderer = gtk_cell_renderer_text_new();
1249 	gtk_tree_view_insert_column_with_attributes(view, -1,
1250 						    "Name", renderer,
1251 						    "text", COL_NAME,
1252 						    "foreground-rgba",
1253 						    COL_COLOR, NULL);
1254 	renderer = gtk_cell_renderer_text_new();
1255 	gtk_tree_view_insert_column_with_attributes(view, -1,
1256 						    "N", renderer,
1257 						    "text", COL_NO,
1258 						    "foreground-rgba",
1259 						    COL_COLOR, NULL);
1260 	renderer = gtk_cell_renderer_text_new();
1261 	gtk_tree_view_insert_column_with_attributes(view, -1,
1262 						    "M", renderer,
1263 						    "text", COL_MOD,
1264 						    "foreground-rgba",
1265 						    COL_COLOR, NULL);
1266 	renderer = gtk_cell_renderer_text_new();
1267 	gtk_tree_view_insert_column_with_attributes(view, -1,
1268 						    "Y", renderer,
1269 						    "text", COL_YES,
1270 						    "foreground-rgba",
1271 						    COL_COLOR, NULL);
1272 	renderer = gtk_cell_renderer_text_new();
1273 	gtk_tree_view_insert_column_with_attributes(view, -1,
1274 						    "Value", renderer,
1275 						    "text", COL_VALUE,
1276 						    "editable",
1277 						    COL_EDIT,
1278 						    "foreground-rgba",
1279 						    COL_COLOR, NULL);
1280 	g_signal_connect(G_OBJECT(renderer), "edited",
1281 			 G_CALLBACK(renderer_edited), tree2_w);
1282 
1283 	char *env = getenv(SRCTREE);
1284 	gchar *path = g_strconcat(env ? env : g_get_current_dir(), "/scripts/kconfig/icons/menu.xpm", NULL);
1285 	GError *err = NULL;
1286 
1287 	pix_menu = gdk_pixbuf_new_from_file(path, &err);
1288 	g_free(path);
1289 
1290 	if (err) {
1291 		g_warning("Failed to load menu icon: %s", err->message);
1292 		g_error_free(err);
1293 	}
1294 
1295 	for (i = 0; i < COL_VALUE; i++) {
1296 		column = gtk_tree_view_get_column(view, i);
1297 		gtk_tree_view_column_set_resizable(column, TRUE);
1298 	}
1299 
1300 	sel = gtk_tree_view_get_selection(view);
1301 	gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
1302 }
1303 
1304 /* Main */
1305 int main(int ac, char *av[])
1306 {
1307 	const char *name;
1308 	char *env;
1309 	gchar *glade_file;
1310 
1311 	/* GTK stuffs */
1312 	gtk_init(&ac, &av);
1313 
1314 	/* Determine GUI path */
1315 	env = getenv(SRCTREE);
1316 	if (env)
1317 		glade_file = g_strconcat(env, "/scripts/kconfig/gconf.ui", NULL);
1318 	else if (av[0][0] == '/')
1319 		glade_file = g_strconcat(av[0], ".ui", NULL);
1320 	else
1321 		glade_file = g_strconcat(g_get_current_dir(), "/", av[0], ".ui", NULL);
1322 
1323 	/* Conf stuffs */
1324 	if (ac > 1 && av[1][0] == '-') {
1325 		switch (av[1][1]) {
1326 		case 'a':
1327 			//showAll = 1;
1328 			break;
1329 		case 's':
1330 			conf_set_message_callback(NULL);
1331 			break;
1332 		case 'h':
1333 		case '?':
1334 			printf("%s [-s] <config>\n", av[0]);
1335 			exit(0);
1336 		}
1337 		name = av[2];
1338 	} else
1339 		name = av[1];
1340 
1341 	conf_parse(name);
1342 	fixup_rootmenu(&rootmenu);
1343 
1344 	/* Load the interface and connect signals */
1345 	init_main_window(glade_file);
1346 	init_left_tree();
1347 	init_right_tree();
1348 
1349 	conf_read(NULL);
1350 
1351 	set_view_mode(view_mode);
1352 
1353 	gtk_main();
1354 
1355 	return 0;
1356 }
1357