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