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