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