Linux Audio

Check our new training course

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