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