Linux Audio

Check our new training course

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