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