Linux Audio

Check our new training course

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