home *** CD-ROM | disk | FTP | other *** search
/ PC Welt 2006 November (DVD) / PCWELT_11_2006.ISO / casper / filesystem.squashfs / usr / src / linux-headers-2.6.17-6-686 / scripts / kconfig / gconf.c < prev    next >
Encoding:
C/C++ Source or Header  |  2006-08-11  |  40.6 KB  |  1,646 lines

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