cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

gconf.c (38909B)


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