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