Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (C) 2002-2003 Romain Lievin <roms@tilp.info>
0004  */
0005 
0006 #include <stdlib.h>
0007 #include "lkc.h"
0008 #include "images.h"
0009 
0010 #include <glade/glade.h>
0011 #include <gtk/gtk.h>
0012 #include <glib.h>
0013 #include <gdk/gdkkeysyms.h>
0014 
0015 #include <stdio.h>
0016 #include <string.h>
0017 #include <strings.h>
0018 #include <unistd.h>
0019 #include <time.h>
0020 
0021 //#define DEBUG
0022 
0023 enum {
0024     SINGLE_VIEW, SPLIT_VIEW, FULL_VIEW
0025 };
0026 
0027 enum {
0028     OPT_NORMAL, OPT_ALL, OPT_PROMPT
0029 };
0030 
0031 static gint view_mode = FULL_VIEW;
0032 static gboolean show_name = TRUE;
0033 static gboolean show_range = TRUE;
0034 static gboolean show_value = TRUE;
0035 static gboolean resizeable = FALSE;
0036 static int opt_mode = OPT_NORMAL;
0037 
0038 GtkWidget *main_wnd = NULL;
0039 GtkWidget *tree1_w = NULL;  // left  frame
0040 GtkWidget *tree2_w = NULL;  // right frame
0041 GtkWidget *text_w = NULL;
0042 GtkWidget *hpaned = NULL;
0043 GtkWidget *vpaned = NULL;
0044 GtkWidget *back_btn = NULL;
0045 GtkWidget *save_btn = NULL;
0046 GtkWidget *save_menu_item = NULL;
0047 
0048 GtkTextTag *tag1, *tag2;
0049 GdkColor color;
0050 
0051 GtkTreeStore *tree1, *tree2, *tree;
0052 GtkTreeModel *model1, *model2;
0053 static GtkTreeIter *parents[256];
0054 static gint indent;
0055 
0056 static struct menu *current; // current node for SINGLE view
0057 static struct menu *browsed; // browsed node for SPLIT view
0058 
0059 enum {
0060     COL_OPTION, COL_NAME, COL_NO, COL_MOD, COL_YES, COL_VALUE,
0061     COL_MENU, COL_COLOR, COL_EDIT, COL_PIXBUF,
0062     COL_PIXVIS, COL_BTNVIS, COL_BTNACT, COL_BTNINC, COL_BTNRAD,
0063     COL_NUMBER
0064 };
0065 
0066 static void display_list(void);
0067 static void display_tree(struct menu *menu);
0068 static void display_tree_part(void);
0069 static void update_tree(struct menu *src, GtkTreeIter * dst);
0070 static void set_node(GtkTreeIter * node, struct menu *menu, gchar ** row);
0071 static gchar **fill_row(struct menu *menu);
0072 static void conf_changed(void);
0073 
0074 /* Helping/Debugging Functions */
0075 #ifdef DEBUG
0076 static const char *dbg_sym_flags(int val)
0077 {
0078     static char buf[256];
0079 
0080     bzero(buf, 256);
0081 
0082     if (val & SYMBOL_CONST)
0083         strcat(buf, "const/");
0084     if (val & SYMBOL_CHECK)
0085         strcat(buf, "check/");
0086     if (val & SYMBOL_CHOICE)
0087         strcat(buf, "choice/");
0088     if (val & SYMBOL_CHOICEVAL)
0089         strcat(buf, "choiceval/");
0090     if (val & SYMBOL_VALID)
0091         strcat(buf, "valid/");
0092     if (val & SYMBOL_OPTIONAL)
0093         strcat(buf, "optional/");
0094     if (val & SYMBOL_WRITE)
0095         strcat(buf, "write/");
0096     if (val & SYMBOL_CHANGED)
0097         strcat(buf, "changed/");
0098     if (val & SYMBOL_NO_WRITE)
0099         strcat(buf, "no_write/");
0100 
0101     buf[strlen(buf) - 1] = '\0';
0102 
0103     return buf;
0104 }
0105 #endif
0106 
0107 static void replace_button_icon(GladeXML *xml, GdkDrawable *window,
0108                 GtkStyle *style, gchar *btn_name, gchar **xpm)
0109 {
0110     GdkPixmap *pixmap;
0111     GdkBitmap *mask;
0112     GtkToolButton *button;
0113     GtkWidget *image;
0114 
0115     pixmap = gdk_pixmap_create_from_xpm_d(window, &mask,
0116                           &style->bg[GTK_STATE_NORMAL],
0117                           xpm);
0118 
0119     button = GTK_TOOL_BUTTON(glade_xml_get_widget(xml, btn_name));
0120     image = gtk_image_new_from_pixmap(pixmap, mask);
0121     gtk_widget_show(image);
0122     gtk_tool_button_set_icon_widget(button, image);
0123 }
0124 
0125 /* Main Window Initialization */
0126 static void init_main_window(const gchar *glade_file)
0127 {
0128     GladeXML *xml;
0129     GtkWidget *widget;
0130     GtkTextBuffer *txtbuf;
0131     GtkStyle *style;
0132 
0133     xml = glade_xml_new(glade_file, "window1", NULL);
0134     if (!xml)
0135         g_error("GUI loading failed !\n");
0136     glade_xml_signal_autoconnect(xml);
0137 
0138     main_wnd = glade_xml_get_widget(xml, "window1");
0139     hpaned = glade_xml_get_widget(xml, "hpaned1");
0140     vpaned = glade_xml_get_widget(xml, "vpaned1");
0141     tree1_w = glade_xml_get_widget(xml, "treeview1");
0142     tree2_w = glade_xml_get_widget(xml, "treeview2");
0143     text_w = glade_xml_get_widget(xml, "textview3");
0144 
0145     back_btn = glade_xml_get_widget(xml, "button1");
0146     gtk_widget_set_sensitive(back_btn, FALSE);
0147 
0148     widget = glade_xml_get_widget(xml, "show_name1");
0149     gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget,
0150                        show_name);
0151 
0152     widget = glade_xml_get_widget(xml, "show_range1");
0153     gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget,
0154                        show_range);
0155 
0156     widget = glade_xml_get_widget(xml, "show_data1");
0157     gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget,
0158                        show_value);
0159 
0160     save_btn = glade_xml_get_widget(xml, "button3");
0161     save_menu_item = glade_xml_get_widget(xml, "save1");
0162     conf_set_changed_callback(conf_changed);
0163 
0164     style = gtk_widget_get_style(main_wnd);
0165     widget = glade_xml_get_widget(xml, "toolbar1");
0166 
0167     replace_button_icon(xml, main_wnd->window, style,
0168                 "button4", (gchar **) xpm_single_view);
0169     replace_button_icon(xml, main_wnd->window, style,
0170                 "button5", (gchar **) xpm_split_view);
0171     replace_button_icon(xml, main_wnd->window, style,
0172                 "button6", (gchar **) xpm_tree_view);
0173 
0174     txtbuf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w));
0175     tag1 = gtk_text_buffer_create_tag(txtbuf, "mytag1",
0176                       "foreground", "red",
0177                       "weight", PANGO_WEIGHT_BOLD,
0178                       NULL);
0179     tag2 = gtk_text_buffer_create_tag(txtbuf, "mytag2",
0180                       /*"style", PANGO_STYLE_OBLIQUE, */
0181                       NULL);
0182 
0183     gtk_window_set_title(GTK_WINDOW(main_wnd), rootmenu.prompt->text);
0184 
0185     gtk_widget_show(main_wnd);
0186 }
0187 
0188 static void init_tree_model(void)
0189 {
0190     gint i;
0191 
0192     tree = tree2 = gtk_tree_store_new(COL_NUMBER,
0193                       G_TYPE_STRING, G_TYPE_STRING,
0194                       G_TYPE_STRING, G_TYPE_STRING,
0195                       G_TYPE_STRING, G_TYPE_STRING,
0196                       G_TYPE_POINTER, GDK_TYPE_COLOR,
0197                       G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF,
0198                       G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
0199                       G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
0200                       G_TYPE_BOOLEAN);
0201     model2 = GTK_TREE_MODEL(tree2);
0202 
0203     for (parents[0] = NULL, i = 1; i < 256; i++)
0204         parents[i] = (GtkTreeIter *) g_malloc(sizeof(GtkTreeIter));
0205 
0206     tree1 = gtk_tree_store_new(COL_NUMBER,
0207                    G_TYPE_STRING, G_TYPE_STRING,
0208                    G_TYPE_STRING, G_TYPE_STRING,
0209                    G_TYPE_STRING, G_TYPE_STRING,
0210                    G_TYPE_POINTER, GDK_TYPE_COLOR,
0211                    G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF,
0212                    G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
0213                    G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
0214                    G_TYPE_BOOLEAN);
0215     model1 = GTK_TREE_MODEL(tree1);
0216 }
0217 
0218 static void init_left_tree(void)
0219 {
0220     GtkTreeView *view = GTK_TREE_VIEW(tree1_w);
0221     GtkCellRenderer *renderer;
0222     GtkTreeSelection *sel;
0223     GtkTreeViewColumn *column;
0224 
0225     gtk_tree_view_set_model(view, model1);
0226     gtk_tree_view_set_headers_visible(view, TRUE);
0227     gtk_tree_view_set_rules_hint(view, TRUE);
0228 
0229     column = gtk_tree_view_column_new();
0230     gtk_tree_view_append_column(view, column);
0231     gtk_tree_view_column_set_title(column, "Options");
0232 
0233     renderer = gtk_cell_renderer_toggle_new();
0234     gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
0235                     renderer, FALSE);
0236     gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
0237                         renderer,
0238                         "active", COL_BTNACT,
0239                         "inconsistent", COL_BTNINC,
0240                         "visible", COL_BTNVIS,
0241                         "radio", COL_BTNRAD, NULL);
0242     renderer = gtk_cell_renderer_text_new();
0243     gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
0244                     renderer, FALSE);
0245     gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
0246                         renderer,
0247                         "text", COL_OPTION,
0248                         "foreground-gdk",
0249                         COL_COLOR, NULL);
0250 
0251     sel = gtk_tree_view_get_selection(view);
0252     gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
0253     gtk_widget_realize(tree1_w);
0254 }
0255 
0256 static void renderer_edited(GtkCellRendererText * cell,
0257                 const gchar * path_string,
0258                 const gchar * new_text, gpointer user_data);
0259 
0260 static void init_right_tree(void)
0261 {
0262     GtkTreeView *view = GTK_TREE_VIEW(tree2_w);
0263     GtkCellRenderer *renderer;
0264     GtkTreeSelection *sel;
0265     GtkTreeViewColumn *column;
0266     gint i;
0267 
0268     gtk_tree_view_set_model(view, model2);
0269     gtk_tree_view_set_headers_visible(view, TRUE);
0270     gtk_tree_view_set_rules_hint(view, TRUE);
0271 
0272     column = gtk_tree_view_column_new();
0273     gtk_tree_view_append_column(view, column);
0274     gtk_tree_view_column_set_title(column, "Options");
0275 
0276     renderer = gtk_cell_renderer_pixbuf_new();
0277     gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
0278                     renderer, FALSE);
0279     gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
0280                         renderer,
0281                         "pixbuf", COL_PIXBUF,
0282                         "visible", COL_PIXVIS, NULL);
0283     renderer = gtk_cell_renderer_toggle_new();
0284     gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
0285                     renderer, FALSE);
0286     gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
0287                         renderer,
0288                         "active", COL_BTNACT,
0289                         "inconsistent", COL_BTNINC,
0290                         "visible", COL_BTNVIS,
0291                         "radio", COL_BTNRAD, NULL);
0292     renderer = gtk_cell_renderer_text_new();
0293     gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
0294                     renderer, FALSE);
0295     gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
0296                         renderer,
0297                         "text", COL_OPTION,
0298                         "foreground-gdk",
0299                         COL_COLOR, NULL);
0300 
0301     renderer = gtk_cell_renderer_text_new();
0302     gtk_tree_view_insert_column_with_attributes(view, -1,
0303                             "Name", renderer,
0304                             "text", COL_NAME,
0305                             "foreground-gdk",
0306                             COL_COLOR, NULL);
0307     renderer = gtk_cell_renderer_text_new();
0308     gtk_tree_view_insert_column_with_attributes(view, -1,
0309                             "N", renderer,
0310                             "text", COL_NO,
0311                             "foreground-gdk",
0312                             COL_COLOR, NULL);
0313     renderer = gtk_cell_renderer_text_new();
0314     gtk_tree_view_insert_column_with_attributes(view, -1,
0315                             "M", renderer,
0316                             "text", COL_MOD,
0317                             "foreground-gdk",
0318                             COL_COLOR, NULL);
0319     renderer = gtk_cell_renderer_text_new();
0320     gtk_tree_view_insert_column_with_attributes(view, -1,
0321                             "Y", renderer,
0322                             "text", COL_YES,
0323                             "foreground-gdk",
0324                             COL_COLOR, NULL);
0325     renderer = gtk_cell_renderer_text_new();
0326     gtk_tree_view_insert_column_with_attributes(view, -1,
0327                             "Value", renderer,
0328                             "text", COL_VALUE,
0329                             "editable",
0330                             COL_EDIT,
0331                             "foreground-gdk",
0332                             COL_COLOR, NULL);
0333     g_signal_connect(G_OBJECT(renderer), "edited",
0334              G_CALLBACK(renderer_edited), NULL);
0335 
0336     column = gtk_tree_view_get_column(view, COL_NAME);
0337     gtk_tree_view_column_set_visible(column, show_name);
0338     column = gtk_tree_view_get_column(view, COL_NO);
0339     gtk_tree_view_column_set_visible(column, show_range);
0340     column = gtk_tree_view_get_column(view, COL_MOD);
0341     gtk_tree_view_column_set_visible(column, show_range);
0342     column = gtk_tree_view_get_column(view, COL_YES);
0343     gtk_tree_view_column_set_visible(column, show_range);
0344     column = gtk_tree_view_get_column(view, COL_VALUE);
0345     gtk_tree_view_column_set_visible(column, show_value);
0346 
0347     if (resizeable) {
0348         for (i = 0; i < COL_VALUE; i++) {
0349             column = gtk_tree_view_get_column(view, i);
0350             gtk_tree_view_column_set_resizable(column, TRUE);
0351         }
0352     }
0353 
0354     sel = gtk_tree_view_get_selection(view);
0355     gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
0356 }
0357 
0358 
0359 /* Utility Functions */
0360 
0361 
0362 static void text_insert_help(struct menu *menu)
0363 {
0364     GtkTextBuffer *buffer;
0365     GtkTextIter start, end;
0366     const char *prompt = menu_get_prompt(menu);
0367     struct gstr help = str_new();
0368 
0369     menu_get_ext_help(menu, &help);
0370 
0371     buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w));
0372     gtk_text_buffer_get_bounds(buffer, &start, &end);
0373     gtk_text_buffer_delete(buffer, &start, &end);
0374     gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_w), 15);
0375 
0376     gtk_text_buffer_get_end_iter(buffer, &end);
0377     gtk_text_buffer_insert_with_tags(buffer, &end, prompt, -1, tag1,
0378                      NULL);
0379     gtk_text_buffer_insert_at_cursor(buffer, "\n\n", 2);
0380     gtk_text_buffer_get_end_iter(buffer, &end);
0381     gtk_text_buffer_insert_with_tags(buffer, &end, str_get(&help), -1, tag2,
0382                      NULL);
0383     str_free(&help);
0384 }
0385 
0386 
0387 static void text_insert_msg(const char *title, const char *message)
0388 {
0389     GtkTextBuffer *buffer;
0390     GtkTextIter start, end;
0391     const char *msg = message;
0392 
0393     buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w));
0394     gtk_text_buffer_get_bounds(buffer, &start, &end);
0395     gtk_text_buffer_delete(buffer, &start, &end);
0396     gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_w), 15);
0397 
0398     gtk_text_buffer_get_end_iter(buffer, &end);
0399     gtk_text_buffer_insert_with_tags(buffer, &end, title, -1, tag1,
0400                      NULL);
0401     gtk_text_buffer_insert_at_cursor(buffer, "\n\n", 2);
0402     gtk_text_buffer_get_end_iter(buffer, &end);
0403     gtk_text_buffer_insert_with_tags(buffer, &end, msg, -1, tag2,
0404                      NULL);
0405 }
0406 
0407 
0408 /* Main Windows Callbacks */
0409 
0410 void on_save_activate(GtkMenuItem * menuitem, gpointer user_data);
0411 gboolean on_window1_delete_event(GtkWidget * widget, GdkEvent * event,
0412                  gpointer user_data)
0413 {
0414     GtkWidget *dialog, *label;
0415     gint result;
0416 
0417     if (!conf_get_changed())
0418         return FALSE;
0419 
0420     dialog = gtk_dialog_new_with_buttons("Warning !",
0421                          GTK_WINDOW(main_wnd),
0422                          (GtkDialogFlags)
0423                          (GTK_DIALOG_MODAL |
0424                           GTK_DIALOG_DESTROY_WITH_PARENT),
0425                          GTK_STOCK_OK,
0426                          GTK_RESPONSE_YES,
0427                          GTK_STOCK_NO,
0428                          GTK_RESPONSE_NO,
0429                          GTK_STOCK_CANCEL,
0430                          GTK_RESPONSE_CANCEL, NULL);
0431     gtk_dialog_set_default_response(GTK_DIALOG(dialog),
0432                     GTK_RESPONSE_CANCEL);
0433 
0434     label = gtk_label_new("\nSave configuration ?\n");
0435     gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), label);
0436     gtk_widget_show(label);
0437 
0438     result = gtk_dialog_run(GTK_DIALOG(dialog));
0439     switch (result) {
0440     case GTK_RESPONSE_YES:
0441         on_save_activate(NULL, NULL);
0442         return FALSE;
0443     case GTK_RESPONSE_NO:
0444         return FALSE;
0445     case GTK_RESPONSE_CANCEL:
0446     case GTK_RESPONSE_DELETE_EVENT:
0447     default:
0448         gtk_widget_destroy(dialog);
0449         return TRUE;
0450     }
0451 
0452     return FALSE;
0453 }
0454 
0455 
0456 void on_window1_destroy(GtkObject * object, gpointer user_data)
0457 {
0458     gtk_main_quit();
0459 }
0460 
0461 
0462 void
0463 on_window1_size_request(GtkWidget * widget,
0464             GtkRequisition * requisition, gpointer user_data)
0465 {
0466     static gint old_h;
0467     gint w, h;
0468 
0469     if (widget->window == NULL)
0470         gtk_window_get_default_size(GTK_WINDOW(main_wnd), &w, &h);
0471     else
0472         gdk_window_get_size(widget->window, &w, &h);
0473 
0474     if (h == old_h)
0475         return;
0476     old_h = h;
0477 
0478     gtk_paned_set_position(GTK_PANED(vpaned), 2 * h / 3);
0479 }
0480 
0481 
0482 /* Menu & Toolbar Callbacks */
0483 
0484 
0485 static void
0486 load_filename(GtkFileSelection * file_selector, gpointer user_data)
0487 {
0488     const gchar *fn;
0489 
0490     fn = gtk_file_selection_get_filename(GTK_FILE_SELECTION
0491                          (user_data));
0492 
0493     if (conf_read(fn))
0494         text_insert_msg("Error", "Unable to load configuration !");
0495     else
0496         display_tree(&rootmenu);
0497 }
0498 
0499 void on_load1_activate(GtkMenuItem * menuitem, gpointer user_data)
0500 {
0501     GtkWidget *fs;
0502 
0503     fs = gtk_file_selection_new("Load file...");
0504     g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs)->ok_button),
0505              "clicked",
0506              G_CALLBACK(load_filename), (gpointer) fs);
0507     g_signal_connect_swapped(GTK_OBJECT
0508                  (GTK_FILE_SELECTION(fs)->ok_button),
0509                  "clicked", G_CALLBACK(gtk_widget_destroy),
0510                  (gpointer) fs);
0511     g_signal_connect_swapped(GTK_OBJECT
0512                  (GTK_FILE_SELECTION(fs)->cancel_button),
0513                  "clicked", G_CALLBACK(gtk_widget_destroy),
0514                  (gpointer) fs);
0515     gtk_widget_show(fs);
0516 }
0517 
0518 
0519 void on_save_activate(GtkMenuItem * menuitem, gpointer user_data)
0520 {
0521     if (conf_write(NULL))
0522         text_insert_msg("Error", "Unable to save configuration !");
0523     conf_write_autoconf(0);
0524 }
0525 
0526 
0527 static void
0528 store_filename(GtkFileSelection * file_selector, gpointer user_data)
0529 {
0530     const gchar *fn;
0531 
0532     fn = gtk_file_selection_get_filename(GTK_FILE_SELECTION
0533                          (user_data));
0534 
0535     if (conf_write(fn))
0536         text_insert_msg("Error", "Unable to save configuration !");
0537 
0538     gtk_widget_destroy(GTK_WIDGET(user_data));
0539 }
0540 
0541 void on_save_as1_activate(GtkMenuItem * menuitem, gpointer user_data)
0542 {
0543     GtkWidget *fs;
0544 
0545     fs = gtk_file_selection_new("Save file as...");
0546     g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs)->ok_button),
0547              "clicked",
0548              G_CALLBACK(store_filename), (gpointer) fs);
0549     g_signal_connect_swapped(GTK_OBJECT
0550                  (GTK_FILE_SELECTION(fs)->ok_button),
0551                  "clicked", G_CALLBACK(gtk_widget_destroy),
0552                  (gpointer) fs);
0553     g_signal_connect_swapped(GTK_OBJECT
0554                  (GTK_FILE_SELECTION(fs)->cancel_button),
0555                  "clicked", G_CALLBACK(gtk_widget_destroy),
0556                  (gpointer) fs);
0557     gtk_widget_show(fs);
0558 }
0559 
0560 
0561 void on_quit1_activate(GtkMenuItem * menuitem, gpointer user_data)
0562 {
0563     if (!on_window1_delete_event(NULL, NULL, NULL))
0564         gtk_widget_destroy(GTK_WIDGET(main_wnd));
0565 }
0566 
0567 
0568 void on_show_name1_activate(GtkMenuItem * menuitem, gpointer user_data)
0569 {
0570     GtkTreeViewColumn *col;
0571 
0572     show_name = GTK_CHECK_MENU_ITEM(menuitem)->active;
0573     col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_NAME);
0574     if (col)
0575         gtk_tree_view_column_set_visible(col, show_name);
0576 }
0577 
0578 
0579 void on_show_range1_activate(GtkMenuItem * menuitem, gpointer user_data)
0580 {
0581     GtkTreeViewColumn *col;
0582 
0583     show_range = GTK_CHECK_MENU_ITEM(menuitem)->active;
0584     col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_NO);
0585     if (col)
0586         gtk_tree_view_column_set_visible(col, show_range);
0587     col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_MOD);
0588     if (col)
0589         gtk_tree_view_column_set_visible(col, show_range);
0590     col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_YES);
0591     if (col)
0592         gtk_tree_view_column_set_visible(col, show_range);
0593 
0594 }
0595 
0596 
0597 void on_show_data1_activate(GtkMenuItem * menuitem, gpointer user_data)
0598 {
0599     GtkTreeViewColumn *col;
0600 
0601     show_value = GTK_CHECK_MENU_ITEM(menuitem)->active;
0602     col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_VALUE);
0603     if (col)
0604         gtk_tree_view_column_set_visible(col, show_value);
0605 }
0606 
0607 
0608 void
0609 on_set_option_mode1_activate(GtkMenuItem *menuitem, gpointer user_data)
0610 {
0611     opt_mode = OPT_NORMAL;
0612     gtk_tree_store_clear(tree2);
0613     display_tree(&rootmenu);    /* instead of update_tree to speed-up */
0614 }
0615 
0616 
0617 void
0618 on_set_option_mode2_activate(GtkMenuItem *menuitem, gpointer user_data)
0619 {
0620     opt_mode = OPT_ALL;
0621     gtk_tree_store_clear(tree2);
0622     display_tree(&rootmenu);    /* instead of update_tree to speed-up */
0623 }
0624 
0625 
0626 void
0627 on_set_option_mode3_activate(GtkMenuItem *menuitem, gpointer user_data)
0628 {
0629     opt_mode = OPT_PROMPT;
0630     gtk_tree_store_clear(tree2);
0631     display_tree(&rootmenu);    /* instead of update_tree to speed-up */
0632 }
0633 
0634 
0635 void on_introduction1_activate(GtkMenuItem * menuitem, gpointer user_data)
0636 {
0637     GtkWidget *dialog;
0638     const gchar *intro_text =
0639         "Welcome to gkc, the GTK+ graphical configuration tool\n"
0640         "For each option, a blank box indicates the feature is disabled, a\n"
0641         "check indicates it is enabled, and a dot indicates that it is to\n"
0642         "be compiled as a module.  Clicking on the box will cycle through the three states.\n"
0643         "\n"
0644         "If you do not see an option (e.g., a device driver) that you\n"
0645         "believe should be present, try turning on Show All Options\n"
0646         "under the Options menu.\n"
0647         "Although there is no cross reference yet to help you figure out\n"
0648         "what other options must be enabled to support the option you\n"
0649         "are interested in, you can still view the help of a grayed-out\n"
0650         "option.\n"
0651         "\n"
0652         "Toggling Show Debug Info under the Options menu will show \n"
0653         "the dependencies, which you can then match by examining other options.";
0654 
0655     dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
0656                     GTK_DIALOG_DESTROY_WITH_PARENT,
0657                     GTK_MESSAGE_INFO,
0658                     GTK_BUTTONS_CLOSE, "%s", intro_text);
0659     g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
0660                  G_CALLBACK(gtk_widget_destroy),
0661                  GTK_OBJECT(dialog));
0662     gtk_widget_show_all(dialog);
0663 }
0664 
0665 
0666 void on_about1_activate(GtkMenuItem * menuitem, gpointer user_data)
0667 {
0668     GtkWidget *dialog;
0669     const gchar *about_text =
0670         "gkc is copyright (c) 2002 Romain Lievin <roms@lpg.ticalc.org>.\n"
0671           "Based on the source code from Roman Zippel.\n";
0672 
0673     dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
0674                     GTK_DIALOG_DESTROY_WITH_PARENT,
0675                     GTK_MESSAGE_INFO,
0676                     GTK_BUTTONS_CLOSE, "%s", about_text);
0677     g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
0678                  G_CALLBACK(gtk_widget_destroy),
0679                  GTK_OBJECT(dialog));
0680     gtk_widget_show_all(dialog);
0681 }
0682 
0683 
0684 void on_license1_activate(GtkMenuItem * menuitem, gpointer user_data)
0685 {
0686     GtkWidget *dialog;
0687     const gchar *license_text =
0688         "gkc is released under the terms of the GNU GPL v2.\n"
0689           "For more information, please see the source code or\n"
0690           "visit http://www.fsf.org/licenses/licenses.html\n";
0691 
0692     dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
0693                     GTK_DIALOG_DESTROY_WITH_PARENT,
0694                     GTK_MESSAGE_INFO,
0695                     GTK_BUTTONS_CLOSE, "%s", license_text);
0696     g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
0697                  G_CALLBACK(gtk_widget_destroy),
0698                  GTK_OBJECT(dialog));
0699     gtk_widget_show_all(dialog);
0700 }
0701 
0702 
0703 void on_back_clicked(GtkButton * button, gpointer user_data)
0704 {
0705     enum prop_type ptype;
0706 
0707     current = current->parent;
0708     ptype = current->prompt ? current->prompt->type : P_UNKNOWN;
0709     if (ptype != P_MENU)
0710         current = current->parent;
0711     display_tree_part();
0712 
0713     if (current == &rootmenu)
0714         gtk_widget_set_sensitive(back_btn, FALSE);
0715 }
0716 
0717 
0718 void on_load_clicked(GtkButton * button, gpointer user_data)
0719 {
0720     on_load1_activate(NULL, user_data);
0721 }
0722 
0723 
0724 void on_single_clicked(GtkButton * button, gpointer user_data)
0725 {
0726     view_mode = SINGLE_VIEW;
0727     gtk_widget_hide(tree1_w);
0728     current = &rootmenu;
0729     display_tree_part();
0730 }
0731 
0732 
0733 void on_split_clicked(GtkButton * button, gpointer user_data)
0734 {
0735     gint w, h;
0736     view_mode = SPLIT_VIEW;
0737     gtk_widget_show(tree1_w);
0738     gtk_window_get_default_size(GTK_WINDOW(main_wnd), &w, &h);
0739     gtk_paned_set_position(GTK_PANED(hpaned), w / 2);
0740     if (tree2)
0741         gtk_tree_store_clear(tree2);
0742     display_list();
0743 
0744     /* Disable back btn, like in full mode. */
0745     gtk_widget_set_sensitive(back_btn, FALSE);
0746 }
0747 
0748 
0749 void on_full_clicked(GtkButton * button, gpointer user_data)
0750 {
0751     view_mode = FULL_VIEW;
0752     gtk_widget_hide(tree1_w);
0753     if (tree2)
0754         gtk_tree_store_clear(tree2);
0755     display_tree(&rootmenu);
0756     gtk_widget_set_sensitive(back_btn, FALSE);
0757 }
0758 
0759 
0760 void on_collapse_clicked(GtkButton * button, gpointer user_data)
0761 {
0762     gtk_tree_view_collapse_all(GTK_TREE_VIEW(tree2_w));
0763 }
0764 
0765 
0766 void on_expand_clicked(GtkButton * button, gpointer user_data)
0767 {
0768     gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w));
0769 }
0770 
0771 
0772 /* CTree Callbacks */
0773 
0774 /* Change hex/int/string value in the cell */
0775 static void renderer_edited(GtkCellRendererText * cell,
0776                 const gchar * path_string,
0777                 const gchar * new_text, gpointer user_data)
0778 {
0779     GtkTreePath *path = gtk_tree_path_new_from_string(path_string);
0780     GtkTreeIter iter;
0781     const char *old_def, *new_def;
0782     struct menu *menu;
0783     struct symbol *sym;
0784 
0785     if (!gtk_tree_model_get_iter(model2, &iter, path))
0786         return;
0787 
0788     gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
0789     sym = menu->sym;
0790 
0791     gtk_tree_model_get(model2, &iter, COL_VALUE, &old_def, -1);
0792     new_def = new_text;
0793 
0794     sym_set_string_value(sym, new_def);
0795 
0796     update_tree(&rootmenu, NULL);
0797 
0798     gtk_tree_path_free(path);
0799 }
0800 
0801 /* Change the value of a symbol and update the tree */
0802 static void change_sym_value(struct menu *menu, gint col)
0803 {
0804     struct symbol *sym = menu->sym;
0805     tristate newval;
0806 
0807     if (!sym)
0808         return;
0809 
0810     if (col == COL_NO)
0811         newval = no;
0812     else if (col == COL_MOD)
0813         newval = mod;
0814     else if (col == COL_YES)
0815         newval = yes;
0816     else
0817         return;
0818 
0819     switch (sym_get_type(sym)) {
0820     case S_BOOLEAN:
0821     case S_TRISTATE:
0822         if (!sym_tristate_within_range(sym, newval))
0823             newval = yes;
0824         sym_set_tristate_value(sym, newval);
0825         if (view_mode == FULL_VIEW)
0826             update_tree(&rootmenu, NULL);
0827         else if (view_mode == SPLIT_VIEW) {
0828             update_tree(browsed, NULL);
0829             display_list();
0830         }
0831         else if (view_mode == SINGLE_VIEW)
0832             display_tree_part();    //fixme: keep exp/coll
0833         break;
0834     case S_INT:
0835     case S_HEX:
0836     case S_STRING:
0837     default:
0838         break;
0839     }
0840 }
0841 
0842 static void toggle_sym_value(struct menu *menu)
0843 {
0844     if (!menu->sym)
0845         return;
0846 
0847     sym_toggle_tristate_value(menu->sym);
0848     if (view_mode == FULL_VIEW)
0849         update_tree(&rootmenu, NULL);
0850     else if (view_mode == SPLIT_VIEW) {
0851         update_tree(browsed, NULL);
0852         display_list();
0853     }
0854     else if (view_mode == SINGLE_VIEW)
0855         display_tree_part();    //fixme: keep exp/coll
0856 }
0857 
0858 static gint column2index(GtkTreeViewColumn * column)
0859 {
0860     gint i;
0861 
0862     for (i = 0; i < COL_NUMBER; i++) {
0863         GtkTreeViewColumn *col;
0864 
0865         col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), i);
0866         if (col == column)
0867             return i;
0868     }
0869 
0870     return -1;
0871 }
0872 
0873 
0874 /* User click: update choice (full) or goes down (single) */
0875 gboolean
0876 on_treeview2_button_press_event(GtkWidget * widget,
0877                 GdkEventButton * event, gpointer user_data)
0878 {
0879     GtkTreeView *view = GTK_TREE_VIEW(widget);
0880     GtkTreePath *path;
0881     GtkTreeViewColumn *column;
0882     GtkTreeIter iter;
0883     struct menu *menu;
0884     gint col;
0885 
0886 #if GTK_CHECK_VERSION(2,1,4) // bug in ctree with earlier version of GTK
0887     gint tx = (gint) event->x;
0888     gint ty = (gint) event->y;
0889     gint cx, cy;
0890 
0891     gtk_tree_view_get_path_at_pos(view, tx, ty, &path, &column, &cx,
0892                       &cy);
0893 #else
0894     gtk_tree_view_get_cursor(view, &path, &column);
0895 #endif
0896     if (path == NULL)
0897         return FALSE;
0898 
0899     if (!gtk_tree_model_get_iter(model2, &iter, path))
0900         return FALSE;
0901     gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
0902 
0903     col = column2index(column);
0904     if (event->type == GDK_2BUTTON_PRESS) {
0905         enum prop_type ptype;
0906         ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
0907 
0908         if (ptype == P_MENU && view_mode != FULL_VIEW && col == COL_OPTION) {
0909             // goes down into menu
0910             current = menu;
0911             display_tree_part();
0912             gtk_widget_set_sensitive(back_btn, TRUE);
0913         } else if (col == COL_OPTION) {
0914             toggle_sym_value(menu);
0915             gtk_tree_view_expand_row(view, path, TRUE);
0916         }
0917     } else {
0918         if (col == COL_VALUE) {
0919             toggle_sym_value(menu);
0920             gtk_tree_view_expand_row(view, path, TRUE);
0921         } else if (col == COL_NO || col == COL_MOD
0922                || col == COL_YES) {
0923             change_sym_value(menu, col);
0924             gtk_tree_view_expand_row(view, path, TRUE);
0925         }
0926     }
0927 
0928     return FALSE;
0929 }
0930 
0931 /* Key pressed: update choice */
0932 gboolean
0933 on_treeview2_key_press_event(GtkWidget * widget,
0934                  GdkEventKey * event, gpointer user_data)
0935 {
0936     GtkTreeView *view = GTK_TREE_VIEW(widget);
0937     GtkTreePath *path;
0938     GtkTreeViewColumn *column;
0939     GtkTreeIter iter;
0940     struct menu *menu;
0941     gint col;
0942 
0943     gtk_tree_view_get_cursor(view, &path, &column);
0944     if (path == NULL)
0945         return FALSE;
0946 
0947     if (event->keyval == GDK_space) {
0948         if (gtk_tree_view_row_expanded(view, path))
0949             gtk_tree_view_collapse_row(view, path);
0950         else
0951             gtk_tree_view_expand_row(view, path, FALSE);
0952         return TRUE;
0953     }
0954     if (event->keyval == GDK_KP_Enter) {
0955     }
0956     if (widget == tree1_w)
0957         return FALSE;
0958 
0959     gtk_tree_model_get_iter(model2, &iter, path);
0960     gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
0961 
0962     if (!strcasecmp(event->string, "n"))
0963         col = COL_NO;
0964     else if (!strcasecmp(event->string, "m"))
0965         col = COL_MOD;
0966     else if (!strcasecmp(event->string, "y"))
0967         col = COL_YES;
0968     else
0969         col = -1;
0970     change_sym_value(menu, col);
0971 
0972     return FALSE;
0973 }
0974 
0975 
0976 /* Row selection changed: update help */
0977 void
0978 on_treeview2_cursor_changed(GtkTreeView * treeview, gpointer user_data)
0979 {
0980     GtkTreeSelection *selection;
0981     GtkTreeIter iter;
0982     struct menu *menu;
0983 
0984     selection = gtk_tree_view_get_selection(treeview);
0985     if (gtk_tree_selection_get_selected(selection, &model2, &iter)) {
0986         gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
0987         text_insert_help(menu);
0988     }
0989 }
0990 
0991 
0992 /* User click: display sub-tree in the right frame. */
0993 gboolean
0994 on_treeview1_button_press_event(GtkWidget * widget,
0995                 GdkEventButton * event, gpointer user_data)
0996 {
0997     GtkTreeView *view = GTK_TREE_VIEW(widget);
0998     GtkTreePath *path;
0999     GtkTreeViewColumn *column;
1000     GtkTreeIter iter;
1001     struct menu *menu;
1002 
1003     gint tx = (gint) event->x;
1004     gint ty = (gint) event->y;
1005     gint cx, cy;
1006 
1007     gtk_tree_view_get_path_at_pos(view, tx, ty, &path, &column, &cx,
1008                       &cy);
1009     if (path == NULL)
1010         return FALSE;
1011 
1012     gtk_tree_model_get_iter(model1, &iter, path);
1013     gtk_tree_model_get(model1, &iter, COL_MENU, &menu, -1);
1014 
1015     if (event->type == GDK_2BUTTON_PRESS) {
1016         toggle_sym_value(menu);
1017         current = menu;
1018         display_tree_part();
1019     } else {
1020         browsed = menu;
1021         display_tree_part();
1022     }
1023 
1024     gtk_widget_realize(tree2_w);
1025     gtk_tree_view_set_cursor(view, path, NULL, FALSE);
1026     gtk_widget_grab_focus(tree2_w);
1027 
1028     return FALSE;
1029 }
1030 
1031 
1032 /* Fill a row of strings */
1033 static gchar **fill_row(struct menu *menu)
1034 {
1035     static gchar *row[COL_NUMBER];
1036     struct symbol *sym = menu->sym;
1037     const char *def;
1038     int stype;
1039     tristate val;
1040     enum prop_type ptype;
1041     int i;
1042 
1043     for (i = COL_OPTION; i <= COL_COLOR; i++)
1044         g_free(row[i]);
1045     bzero(row, sizeof(row));
1046 
1047     ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
1048 
1049     row[COL_OPTION] =
1050         g_strdup_printf("%s %s %s %s",
1051                 ptype == P_COMMENT ? "***" : "",
1052                 menu_get_prompt(menu),
1053                 ptype == P_COMMENT ? "***" : "",
1054                 sym && !sym_has_value(sym) ? "(NEW)" : "");
1055 
1056     if (opt_mode == OPT_ALL && !menu_is_visible(menu))
1057         row[COL_COLOR] = g_strdup("DarkGray");
1058     else if (opt_mode == OPT_PROMPT &&
1059             menu_has_prompt(menu) && !menu_is_visible(menu))
1060         row[COL_COLOR] = g_strdup("DarkGray");
1061     else
1062         row[COL_COLOR] = g_strdup("Black");
1063 
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     /* Determine GUI path */
1456     env = getenv(SRCTREE);
1457     if (env)
1458         glade_file = g_strconcat(env, "/scripts/kconfig/gconf.glade", NULL);
1459     else if (av[0][0] == '/')
1460         glade_file = g_strconcat(av[0], ".glade", NULL);
1461     else
1462         glade_file = g_strconcat(g_get_current_dir(), "/", av[0], ".glade", NULL);
1463 
1464     /* Conf stuffs */
1465     if (ac > 1 && av[1][0] == '-') {
1466         switch (av[1][1]) {
1467         case 'a':
1468             //showAll = 1;
1469             break;
1470         case 's':
1471             conf_set_message_callback(NULL);
1472             break;
1473         case 'h':
1474         case '?':
1475             printf("%s [-s] <config>\n", av[0]);
1476             exit(0);
1477         }
1478         name = av[2];
1479     } else
1480         name = av[1];
1481 
1482     conf_parse(name);
1483     fixup_rootmenu(&rootmenu);
1484     conf_read(NULL);
1485 
1486     /* Load the interface and connect signals */
1487     init_main_window(glade_file);
1488     init_tree_model();
1489     init_left_tree();
1490     init_right_tree();
1491 
1492     switch (view_mode) {
1493     case SINGLE_VIEW:
1494         display_tree_part();
1495         break;
1496     case SPLIT_VIEW:
1497         display_list();
1498         break;
1499     case FULL_VIEW:
1500         display_tree(&rootmenu);
1501         break;
1502     }
1503 
1504     gtk_main();
1505 
1506     return 0;
1507 }
1508 
1509 static void conf_changed(void)
1510 {
1511     bool changed = conf_get_changed();
1512     gtk_widget_set_sensitive(save_btn, changed);
1513     gtk_widget_set_sensitive(save_menu_item, changed);
1514 }