File Index
Files and directories
Sign in
FILE

gconf.c

File preview with syntax highlighting.

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