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