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