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