Linux Audio

Check our new training course

Loading...
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}
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}