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