coreboot/util/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, _("coreboot 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        if (conf_write_autoconf())
 629                text_insert_msg(_("Error"), _("Unable to save configuration !"));
 630}
 631
 632
 633static void
 634store_filename(GtkFileSelection * file_selector, gpointer user_data)
 635{
 636        const gchar *fn;
 637
 638        fn = gtk_file_selection_get_filename(GTK_FILE_SELECTION
 639                                             (user_data));
 640
 641        if (conf_write(fn))
 642                text_insert_msg(_("Error"), _("Unable to save configuration !"));
 643        if (conf_write_autoconf())
 644                text_insert_msg(_("Error"), _("Unable to save configuration !"));
 645
 646        gtk_widget_destroy(GTK_WIDGET(user_data));
 647}
 648
 649void on_save_as1_activate(GtkMenuItem * menuitem, gpointer user_data)
 650{
 651        GtkWidget *fs;
 652
 653        fs = gtk_file_selection_new(_("Save file as..."));
 654        g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs)->ok_button),
 655                         "clicked",
 656                         G_CALLBACK(store_filename), (gpointer) fs);
 657        g_signal_connect_swapped(GTK_OBJECT
 658                                 (GTK_FILE_SELECTION(fs)->ok_button),
 659                                 "clicked", G_CALLBACK(gtk_widget_destroy),
 660                                 (gpointer) fs);
 661        g_signal_connect_swapped(GTK_OBJECT
 662                                 (GTK_FILE_SELECTION(fs)->cancel_button),
 663                                 "clicked", G_CALLBACK(gtk_widget_destroy),
 664                                 (gpointer) fs);
 665        gtk_widget_show(fs);
 666}
 667
 668
 669void on_quit1_activate(GtkMenuItem * menuitem, gpointer user_data)
 670{
 671        if (!on_window1_delete_event(NULL, NULL, NULL))
 672                gtk_widget_destroy(GTK_WIDGET(main_wnd));
 673}
 674
 675
 676void on_show_name1_activate(GtkMenuItem * menuitem, gpointer user_data)
 677{
 678        GtkTreeViewColumn *col;
 679
 680        show_name = GTK_CHECK_MENU_ITEM(menuitem)->active;
 681        col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_NAME);
 682        if (col)
 683                gtk_tree_view_column_set_visible(col, show_name);
 684}
 685
 686
 687void on_show_range1_activate(GtkMenuItem * menuitem, gpointer user_data)
 688{
 689        GtkTreeViewColumn *col;
 690
 691        show_range = GTK_CHECK_MENU_ITEM(menuitem)->active;
 692        col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_NO);
 693        if (col)
 694                gtk_tree_view_column_set_visible(col, show_range);
 695        col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_MOD);
 696        if (col)
 697                gtk_tree_view_column_set_visible(col, show_range);
 698        col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_YES);
 699        if (col)
 700                gtk_tree_view_column_set_visible(col, show_range);
 701
 702}
 703
 704
 705void on_show_data1_activate(GtkMenuItem * menuitem, gpointer user_data)
 706{
 707        GtkTreeViewColumn *col;
 708
 709        show_value = GTK_CHECK_MENU_ITEM(menuitem)->active;
 710        col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_VALUE);
 711        if (col)
 712                gtk_tree_view_column_set_visible(col, show_value);
 713}
 714
 715
 716void
 717on_show_all_options1_activate(GtkMenuItem * menuitem, gpointer user_data)
 718{
 719        show_all = GTK_CHECK_MENU_ITEM(menuitem)->active;
 720
 721        gtk_tree_store_clear(tree2);
 722        display_tree(&rootmenu);        // instead of update_tree to speed-up
 723}
 724
 725
 726void
 727on_show_debug_info1_activate(GtkMenuItem * menuitem, gpointer user_data)
 728{
 729        show_debug = GTK_CHECK_MENU_ITEM(menuitem)->active;
 730        update_tree(&rootmenu, NULL);
 731}
 732
 733
 734void on_introduction1_activate(GtkMenuItem * menuitem, gpointer user_data)
 735{
 736        GtkWidget *dialog;
 737        const gchar *intro_text = _(
 738            "Welcome to gkc, the GTK+ graphical configuration tool\n"
 739            "for coreboot.\n"
 740            "For each option, a blank box indicates the feature is disabled, a\n"
 741            "check indicates it is enabled, and a dot indicates that it is to\n"
 742            "be compiled as a module.  Clicking on the box will cycle through the three states.\n"
 743            "\n"
 744            "If you do not see an option (e.g., a device driver) that you\n"
 745            "believe should be present, try turning on Show All Options\n"
 746            "under the Options menu.\n"
 747            "Although there is no cross reference yet to help you figure out\n"
 748            "what other options must be enabled to support the option you\n"
 749            "are interested in, you can still view the help of a grayed-out\n"
 750            "option.\n"
 751            "\n"
 752            "Toggling Show Debug Info under the Options menu will show \n"
 753            "the dependencies, which you can then match by examining other options.");
 754
 755        dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
 756                                        GTK_DIALOG_DESTROY_WITH_PARENT,
 757                                        GTK_MESSAGE_INFO,
 758                                        GTK_BUTTONS_CLOSE, intro_text);
 759        g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
 760                                 G_CALLBACK(gtk_widget_destroy),
 761                                 GTK_OBJECT(dialog));
 762        gtk_widget_show_all(dialog);
 763}
 764
 765
 766void on_about1_activate(GtkMenuItem * menuitem, gpointer user_data)
 767{
 768        GtkWidget *dialog;
 769        const gchar *about_text =
 770            _("gkc is copyright (c) 2002 Romain Lievin <roms@lpg.ticalc.org>.\n"
 771              "Based on the source code from Roman Zippel.\n");
 772
 773        dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
 774                                        GTK_DIALOG_DESTROY_WITH_PARENT,
 775                                        GTK_MESSAGE_INFO,
 776                                        GTK_BUTTONS_CLOSE, about_text);
 777        g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
 778                                 G_CALLBACK(gtk_widget_destroy),
 779                                 GTK_OBJECT(dialog));
 780        gtk_widget_show_all(dialog);
 781}
 782
 783
 784void on_license1_activate(GtkMenuItem * menuitem, gpointer user_data)
 785{
 786        GtkWidget *dialog;
 787        const gchar *license_text =
 788            _("gkc is released under the terms of the GNU GPL v2.\n"
 789              "For more information, please see the source code or\n"
 790              "visit http://www.fsf.org/licenses/licenses.html\n");
 791
 792        dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
 793                                        GTK_DIALOG_DESTROY_WITH_PARENT,
 794                                        GTK_MESSAGE_INFO,
 795                                        GTK_BUTTONS_CLOSE, license_text);
 796        g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
 797                                 G_CALLBACK(gtk_widget_destroy),
 798                                 GTK_OBJECT(dialog));
 799        gtk_widget_show_all(dialog);
 800}
 801
 802
 803void on_back_clicked(GtkButton * button, gpointer user_data)
 804{
 805        enum prop_type ptype;
 806
 807        current = current->parent;
 808        ptype = current->prompt ? current->prompt->type : P_UNKNOWN;
 809        if (ptype != P_MENU)
 810                current = current->parent;
 811        display_tree_part();
 812
 813        if (current == &rootmenu)
 814                gtk_widget_set_sensitive(back_btn, FALSE);
 815}
 816
 817
 818void on_load_clicked(GtkButton * button, gpointer user_data)
 819{
 820        on_load1_activate(NULL, user_data);
 821}
 822
 823
 824void on_single_clicked(GtkButton * button, gpointer user_data)
 825{
 826        view_mode = SINGLE_VIEW;
 827        gtk_paned_set_position(GTK_PANED(hpaned), 0);
 828        gtk_widget_hide(tree1_w);
 829        current = &rootmenu;
 830        display_tree_part();
 831}
 832
 833
 834void on_split_clicked(GtkButton * button, gpointer user_data)
 835{
 836        gint w, h;
 837        view_mode = SPLIT_VIEW;
 838        gtk_widget_show(tree1_w);
 839        gtk_window_get_default_size(GTK_WINDOW(main_wnd), &w, &h);
 840        gtk_paned_set_position(GTK_PANED(hpaned), w / 2);
 841        if (tree2)
 842                gtk_tree_store_clear(tree2);
 843        display_list();
 844
 845        /* Disable back btn, like in full mode. */
 846        gtk_widget_set_sensitive(back_btn, FALSE);
 847}
 848
 849
 850void on_full_clicked(GtkButton * button, gpointer user_data)
 851{
 852        view_mode = FULL_VIEW;
 853        gtk_paned_set_position(GTK_PANED(hpaned), 0);
 854        gtk_widget_hide(tree1_w);
 855        if (tree2)
 856                gtk_tree_store_clear(tree2);
 857        display_tree(&rootmenu);
 858        gtk_widget_set_sensitive(back_btn, FALSE);
 859}
 860
 861
 862void on_collapse_clicked(GtkButton * button, gpointer user_data)
 863{
 864        gtk_tree_view_collapse_all(GTK_TREE_VIEW(tree2_w));
 865}
 866
 867
 868void on_expand_clicked(GtkButton * button, gpointer user_data)
 869{
 870        gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w));
 871}
 872
 873
 874/* CTree Callbacks */
 875
 876/* Change hex/int/string value in the cell */
 877static void renderer_edited(GtkCellRendererText * cell,
 878                            const gchar * path_string,
 879                            const gchar * new_text, gpointer user_data)
 880{
 881        GtkTreePath *path = gtk_tree_path_new_from_string(path_string);
 882        GtkTreeIter iter;
 883        const char *old_def, *new_def;
 884        struct menu *menu;
 885        struct symbol *sym;
 886
 887        if (!gtk_tree_model_get_iter(model2, &iter, path))
 888                return;
 889
 890        gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
 891        sym = menu->sym;
 892
 893        gtk_tree_model_get(model2, &iter, COL_VALUE, &old_def, -1);
 894        new_def = new_text;
 895
 896        sym_set_string_value(sym, new_def);
 897
 898        update_tree(&rootmenu, NULL);
 899
 900        gtk_tree_path_free(path);
 901}
 902
 903/* Change the value of a symbol and update the tree */
 904static void change_sym_value(struct menu *menu, gint col)
 905{
 906        struct symbol *sym = menu->sym;
 907        tristate oldval, newval;
 908
 909        if (!sym)
 910                return;
 911
 912        if (col == COL_NO)
 913                newval = no;
 914        else if (col == COL_MOD)
 915                newval = mod;
 916        else if (col == COL_YES)
 917                newval = yes;
 918        else
 919                return;
 920
 921        switch (sym_get_type(sym)) {
 922        case S_BOOLEAN:
 923        case S_TRISTATE:
 924                oldval = sym_get_tristate_value(sym);
 925                if (!sym_tristate_within_range(sym, newval))
 926                        newval = yes;
 927                sym_set_tristate_value(sym, newval);
 928                if (view_mode == FULL_VIEW)
 929                        update_tree(&rootmenu, NULL);
 930                else if (view_mode == SPLIT_VIEW) {
 931                        update_tree(browsed, NULL);
 932                        display_list();
 933                }
 934                else if (view_mode == SINGLE_VIEW)
 935                        display_tree_part();    //fixme: keep exp/coll
 936                break;
 937        case S_INT:
 938        case S_HEX:
 939        case S_STRING:
 940        default:
 941                break;
 942        }
 943}
 944
 945static void toggle_sym_value(struct menu *menu)
 946{
 947        if (!menu->sym)
 948                return;
 949
 950        sym_toggle_tristate_value(menu->sym);
 951        if (view_mode == FULL_VIEW)
 952                update_tree(&rootmenu, NULL);
 953        else if (view_mode == SPLIT_VIEW) {
 954                update_tree(browsed, NULL);
 955                display_list();
 956        }
 957        else if (view_mode == SINGLE_VIEW)
 958                display_tree_part();    //fixme: keep exp/coll
 959}
 960
 961static void renderer_toggled(GtkCellRendererToggle * cell,
 962                             gchar * path_string, gpointer user_data)
 963{
 964        GtkTreePath *path, *sel_path = NULL;
 965        GtkTreeIter iter, sel_iter;
 966        GtkTreeSelection *sel;
 967        struct menu *menu;
 968
 969        path = gtk_tree_path_new_from_string(path_string);
 970        if (!gtk_tree_model_get_iter(model2, &iter, path))
 971                return;
 972
 973        sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree2_w));
 974        if (gtk_tree_selection_get_selected(sel, NULL, &sel_iter))
 975                sel_path = gtk_tree_model_get_path(model2, &sel_iter);
 976        if (!sel_path)
 977                goto out1;
 978        if (gtk_tree_path_compare(path, sel_path))
 979                goto out2;
 980
 981        gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
 982        toggle_sym_value(menu);
 983
 984      out2:
 985        gtk_tree_path_free(sel_path);
 986      out1:
 987        gtk_tree_path_free(path);
 988}
 989
 990static gint column2index(GtkTreeViewColumn * column)
 991{
 992        gint i;
 993
 994        for (i = 0; i < COL_NUMBER; i++) {
 995                GtkTreeViewColumn *col;
 996
 997                col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), i);
 998                if (col == column)
 999                        return i;
1000        }
1001
1002        return -1;
1003}
1004
1005
1006/* User click: update choice (full) or goes down (single) */
1007gboolean
1008on_treeview2_button_press_event(GtkWidget * widget,
1009                                GdkEventButton * event, gpointer user_data)
1010{
1011        GtkTreeView *view = GTK_TREE_VIEW(widget);
1012        GtkTreePath *path;
1013        GtkTreeViewColumn *column;
1014        GtkTreeIter iter;
1015        struct menu *menu;
1016        gint col;
1017
1018#if GTK_CHECK_VERSION(2,1,4) // bug in ctree with earlier version of GTK
1019        gint tx = (gint) event->x;
1020        gint ty = (gint) event->y;
1021        gint cx, cy;
1022
1023        gtk_tree_view_get_path_at_pos(view, tx, ty, &path, &column, &cx,
1024                                      &cy);
1025#else
1026        gtk_tree_view_get_cursor(view, &path, &column);
1027#endif
1028        if (path == NULL)
1029                return FALSE;
1030
1031        if (!gtk_tree_model_get_iter(model2, &iter, path))
1032                return FALSE;
1033        gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
1034
1035        col = column2index(column);
1036        if (event->type == GDK_2BUTTON_PRESS) {
1037                enum prop_type ptype;
1038                ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
1039
1040                if (ptype == P_MENU && view_mode != FULL_VIEW && col == COL_OPTION) {
1041                        // goes down into menu
1042                        current = menu;
1043                        display_tree_part();
1044                        gtk_widget_set_sensitive(back_btn, TRUE);
1045                } else if ((col == COL_OPTION)) {
1046                        toggle_sym_value(menu);
1047                        gtk_tree_view_expand_row(view, path, TRUE);
1048                }
1049        } else {
1050                if (col == COL_VALUE) {
1051                        toggle_sym_value(menu);
1052                        gtk_tree_view_expand_row(view, path, TRUE);
1053                } else if (col == COL_NO || col == COL_MOD
1054                           || col == COL_YES) {
1055                        change_sym_value(menu, col);
1056                        gtk_tree_view_expand_row(view, path, TRUE);
1057                }
1058        }
1059
1060        return FALSE;
1061}
1062
1063/* Key pressed: update choice */
1064gboolean
1065on_treeview2_key_press_event(GtkWidget * widget,
1066                             GdkEventKey * event, gpointer user_data)
1067{
1068        GtkTreeView *view = GTK_TREE_VIEW(widget);
1069        GtkTreePath *path;
1070        GtkTreeViewColumn *column;
1071        GtkTreeIter iter;
1072        struct menu *menu;
1073        gint col;
1074
1075        gtk_tree_view_get_cursor(view, &path, &column);
1076        if (path == NULL)
1077                return FALSE;
1078
1079        if (event->keyval == GDK_space) {
1080                if (gtk_tree_view_row_expanded(view, path))
1081                        gtk_tree_view_collapse_row(view, path);
1082                else
1083                        gtk_tree_view_expand_row(view, path, FALSE);
1084                return TRUE;
1085        }
1086        if (event->keyval == GDK_KP_Enter) {
1087        }
1088        if (widget == tree1_w)
1089                return FALSE;
1090
1091        gtk_tree_model_get_iter(model2, &iter, path);
1092        gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
1093
1094        if (!strcasecmp(event->string, "n"))
1095                col = COL_NO;
1096        else if (!strcasecmp(event->string, "m"))
1097                col = COL_MOD;
1098        else if (!strcasecmp(event->string, "y"))
1099                col = COL_YES;
1100        else
1101                col = -1;
1102        change_sym_value(menu, col);
1103
1104        return FALSE;
1105}
1106
1107
1108/* Row selection changed: update help */
1109void
1110on_treeview2_cursor_changed(GtkTreeView * treeview, gpointer user_data)
1111{
1112        GtkTreeSelection *selection;
1113        GtkTreeIter iter;
1114        struct menu *menu;
1115
1116        selection = gtk_tree_view_get_selection(treeview);
1117        if (gtk_tree_selection_get_selected(selection, &model2, &iter)) {
1118                gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
1119                text_insert_help(menu);
1120        }
1121}
1122
1123
1124/* User click: display sub-tree in the right frame. */
1125gboolean
1126on_treeview1_button_press_event(GtkWidget * widget,
1127                                GdkEventButton * event, gpointer user_data)
1128{
1129        GtkTreeView *view = GTK_TREE_VIEW(widget);
1130        GtkTreePath *path;
1131        GtkTreeViewColumn *column;
1132        GtkTreeIter iter;
1133        struct menu *menu;
1134
1135        gint tx = (gint) event->x;
1136        gint ty = (gint) event->y;
1137        gint cx, cy;
1138
1139        gtk_tree_view_get_path_at_pos(view, tx, ty, &path, &column, &cx,
1140                                      &cy);
1141        if (path == NULL)
1142                return FALSE;
1143
1144        gtk_tree_model_get_iter(model1, &iter, path);
1145        gtk_tree_model_get(model1, &iter, COL_MENU, &menu, -1);
1146
1147        if (event->type == GDK_2BUTTON_PRESS) {
1148                toggle_sym_value(menu);
1149                current = menu;
1150                display_tree_part();
1151        } else {
1152                browsed = menu;
1153                display_tree_part();
1154        }
1155
1156        gtk_widget_realize(tree2_w);
1157        gtk_tree_view_set_cursor(view, path, NULL, FALSE);
1158        gtk_widget_grab_focus(tree2_w);
1159
1160        return FALSE;
1161}
1162
1163
1164/* Fill a row of strings */
1165static gchar **fill_row(struct menu *menu)
1166{
1167        static gchar *row[COL_NUMBER];
1168        struct symbol *sym = menu->sym;
1169        const char *def;
1170        int stype;
1171        tristate val;
1172        enum prop_type ptype;
1173        int i;
1174
1175        for (i = COL_OPTION; i <= COL_COLOR; i++)
1176                g_free(row[i]);
1177        bzero(row, sizeof(row));
1178
1179        row[COL_OPTION] =
1180            g_strdup_printf("%s %s", _(menu_get_prompt(menu)),
1181                            sym && sym_has_value(sym) ? "(NEW)" : "");
1182
1183        if (show_all && !menu_is_visible(menu))
1184                row[COL_COLOR] = g_strdup("DarkGray");
1185        else
1186                row[COL_COLOR] = g_strdup("Black");
1187
1188        ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
1189        switch (ptype) {
1190        case P_MENU:
1191                row[COL_PIXBUF] = (gchar *) xpm_menu;
1192                if (view_mode == SINGLE_VIEW)
1193                        row[COL_PIXVIS] = GINT_TO_POINTER(TRUE);
1194                row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
1195                break;
1196        case P_COMMENT:
1197                row[COL_PIXBUF] = (gchar *) xpm_void;
1198                row[COL_PIXVIS] = GINT_TO_POINTER(FALSE);
1199                row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
1200                break;
1201        default:
1202                row[COL_PIXBUF] = (gchar *) xpm_void;
1203                row[COL_PIXVIS] = GINT_TO_POINTER(FALSE);
1204                row[COL_BTNVIS] = GINT_TO_POINTER(TRUE);
1205                break;
1206        }
1207
1208        if (!sym)
1209                return row;
1210        row[COL_NAME] = g_strdup(sym->name);
1211
1212        sym_calc_value(sym);
1213        sym->flags &= ~SYMBOL_CHANGED;
1214
1215        if (sym_is_choice(sym)) {       // parse childs for getting final value
1216                struct menu *child;
1217                struct symbol *def_sym = sym_get_choice_value(sym);
1218                struct menu *def_menu = NULL;
1219
1220                row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
1221
1222                for (child = menu->list; child; child = child->next) {
1223                        if (menu_is_visible(child)
1224                            && child->sym == def_sym)
1225                                def_menu = child;
1226                }
1227
1228                if (def_menu)
1229                        row[COL_VALUE] =
1230                            g_strdup(_(menu_get_prompt(def_menu)));
1231        }
1232        if (sym->flags & SYMBOL_CHOICEVAL)
1233                row[COL_BTNRAD] = GINT_TO_POINTER(TRUE);
1234
1235        stype = sym_get_type(sym);
1236        switch (stype) {
1237        case S_BOOLEAN:
1238                if (GPOINTER_TO_INT(row[COL_PIXVIS]) == FALSE)
1239                        row[COL_BTNVIS] = GINT_TO_POINTER(TRUE);
1240                if (sym_is_choice(sym))
1241                        break;
1242        case S_TRISTATE:
1243                val = sym_get_tristate_value(sym);
1244                switch (val) {
1245                case no:
1246                        row[COL_NO] = g_strdup("N");
1247                        row[COL_VALUE] = g_strdup("N");
1248                        row[COL_BTNACT] = GINT_TO_POINTER(FALSE);
1249                        row[COL_BTNINC] = GINT_TO_POINTER(FALSE);
1250                        break;
1251                case mod:
1252                        row[COL_MOD] = g_strdup("M");
1253                        row[COL_VALUE] = g_strdup("M");
1254                        row[COL_BTNINC] = GINT_TO_POINTER(TRUE);
1255                        break;
1256                case yes:
1257                        row[COL_YES] = g_strdup("Y");
1258                        row[COL_VALUE] = g_strdup("Y");
1259                        row[COL_BTNACT] = GINT_TO_POINTER(TRUE);
1260                        row[COL_BTNINC] = GINT_TO_POINTER(FALSE);
1261                        break;
1262                }
1263
1264                if (val != no && sym_tristate_within_range(sym, no))
1265                        row[COL_NO] = g_strdup("_");
1266                if (val != mod && sym_tristate_within_range(sym, mod))
1267                        row[COL_MOD] = g_strdup("_");
1268                if (val != yes && sym_tristate_within_range(sym, yes))
1269                        row[COL_YES] = g_strdup("_");
1270                break;
1271        case S_INT:
1272        case S_HEX:
1273        case S_STRING:
1274                def = sym_get_string_value(sym);
1275                row[COL_VALUE] = g_strdup(def);
1276                row[COL_EDIT] = GINT_TO_POINTER(TRUE);
1277                row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
1278                break;
1279        }
1280
1281        return row;
1282}
1283
1284
1285/* Set the node content with a row of strings */
1286static void set_node(GtkTreeIter * node, struct menu *menu, gchar ** row)
1287{
1288        GdkColor color;
1289        gboolean success;
1290        GdkPixbuf *pix;
1291
1292        pix = gdk_pixbuf_new_from_xpm_data((const char **)
1293                                           row[COL_PIXBUF]);
1294
1295        gdk_color_parse(row[COL_COLOR], &color);
1296        gdk_colormap_alloc_colors(gdk_colormap_get_system(), &color, 1,
1297                                  FALSE, FALSE, &success);
1298
1299        gtk_tree_store_set(tree, node,
1300                           COL_OPTION, row[COL_OPTION],
1301                           COL_NAME, row[COL_NAME],
1302                           COL_NO, row[COL_NO],
1303                           COL_MOD, row[COL_MOD],
1304                           COL_YES, row[COL_YES],
1305                           COL_VALUE, row[COL_VALUE],
1306                           COL_MENU, (gpointer) menu,
1307                           COL_COLOR, &color,
1308                           COL_EDIT, GPOINTER_TO_INT(row[COL_EDIT]),
1309                           COL_PIXBUF, pix,
1310                           COL_PIXVIS, GPOINTER_TO_INT(row[COL_PIXVIS]),
1311                           COL_BTNVIS, GPOINTER_TO_INT(row[COL_BTNVIS]),
1312                           COL_BTNACT, GPOINTER_TO_INT(row[COL_BTNACT]),
1313                           COL_BTNINC, GPOINTER_TO_INT(row[COL_BTNINC]),
1314                           COL_BTNRAD, GPOINTER_TO_INT(row[COL_BTNRAD]),
1315                           -1);
1316
1317        g_object_unref(pix);
1318}
1319
1320
1321/* Add a node to the tree */
1322static void place_node(struct menu *menu, char **row)
1323{
1324        GtkTreeIter *parent = parents[indent - 1];
1325        GtkTreeIter *node = parents[indent];
1326
1327        gtk_tree_store_append(tree, node, parent);
1328        set_node(node, menu, row);
1329}
1330
1331
1332/* Find a node in the GTK+ tree */
1333static GtkTreeIter found;
1334
1335/*
1336 * Find a menu in the GtkTree starting at parent.
1337 */
1338GtkTreeIter *gtktree_iter_find_node(GtkTreeIter * parent,
1339                                    struct menu *tofind)
1340{
1341        GtkTreeIter iter;
1342        GtkTreeIter *child = &iter;
1343        gboolean valid;
1344        GtkTreeIter *ret;
1345
1346        valid = gtk_tree_model_iter_children(model2, child, parent);
1347        while (valid) {
1348                struct menu *menu;
1349
1350                gtk_tree_model_get(model2, child, 6, &menu, -1);
1351
1352                if (menu == tofind) {
1353                        memcpy(&found, child, sizeof(GtkTreeIter));
1354                        return &found;
1355                }
1356
1357                ret = gtktree_iter_find_node(child, tofind);
1358                if (ret)
1359                        return ret;
1360
1361                valid = gtk_tree_model_iter_next(model2, child);
1362        }
1363
1364        return NULL;
1365}
1366
1367
1368/*
1369 * Update the tree by adding/removing entries
1370 * Does not change other nodes
1371 */
1372static void update_tree(struct menu *src, GtkTreeIter * dst)
1373{
1374        struct menu *child1;
1375        GtkTreeIter iter, tmp;
1376        GtkTreeIter *child2 = &iter;
1377        gboolean valid;
1378        GtkTreeIter *sibling;
1379        struct symbol *sym;
1380        struct property *prop;
1381        struct menu *menu1, *menu2;
1382
1383        if (src == &rootmenu)
1384                indent = 1;
1385
1386        valid = gtk_tree_model_iter_children(model2, child2, dst);
1387        for (child1 = src->list; child1; child1 = child1->next) {
1388
1389                prop = child1->prompt;
1390                sym = child1->sym;
1391
1392              reparse:
1393                menu1 = child1;
1394                if (valid)
1395                        gtk_tree_model_get(model2, child2, COL_MENU,
1396                                           &menu2, -1);
1397                else
1398                        menu2 = NULL;   // force adding of a first child
1399
1400#ifdef DEBUG
1401                printf("%*c%s | %s\n", indent, ' ',
1402                       menu1 ? menu_get_prompt(menu1) : "nil",
1403                       menu2 ? menu_get_prompt(menu2) : "nil");
1404#endif
1405
1406                if (!menu_is_visible(child1) && !show_all) {    // remove node
1407                        if (gtktree_iter_find_node(dst, menu1) != NULL) {
1408                                memcpy(&tmp, child2, sizeof(GtkTreeIter));
1409                                valid = gtk_tree_model_iter_next(model2,
1410                                                                 child2);
1411                                gtk_tree_store_remove(tree2, &tmp);
1412                                if (!valid)
1413                                        return; // next parent
1414                                else
1415                                        goto reparse;   // next child
1416                        } else
1417                                continue;
1418                }
1419
1420                if (menu1 != menu2) {
1421                        if (gtktree_iter_find_node(dst, menu1) == NULL) {       // add node
1422                                if (!valid && !menu2)
1423                                        sibling = NULL;
1424                                else
1425                                        sibling = child2;
1426                                gtk_tree_store_insert_before(tree2,
1427                                                             child2,
1428                                                             dst, sibling);
1429                                set_node(child2, menu1, fill_row(menu1));
1430                                if (menu2 == NULL)
1431                                        valid = TRUE;
1432                        } else {        // remove node
1433                                memcpy(&tmp, child2, sizeof(GtkTreeIter));
1434                                valid = gtk_tree_model_iter_next(model2,
1435                                                                 child2);
1436                                gtk_tree_store_remove(tree2, &tmp);
1437                                if (!valid)
1438                                        return; // next parent
1439                                else
1440                                        goto reparse;   // next child
1441                        }
1442                } else if (sym && (sym->flags & SYMBOL_CHANGED)) {
1443                        set_node(child2, menu1, fill_row(menu1));
1444                }
1445
1446                indent++;
1447                update_tree(child1, child2);
1448                indent--;
1449
1450                valid = gtk_tree_model_iter_next(model2, child2);
1451        }
1452}
1453
1454
1455/* Display the whole tree (single/split/full view) */
1456static void display_tree(struct menu *menu)
1457{
1458        struct symbol *sym;
1459        struct property *prop;
1460        struct menu *child;
1461        enum prop_type ptype;
1462
1463        if (menu == &rootmenu) {
1464                indent = 1;
1465                current = &rootmenu;
1466        }
1467
1468        for (child = menu->list; child; child = child->next) {
1469                prop = child->prompt;
1470                sym = child->sym;
1471                ptype = prop ? prop->type : P_UNKNOWN;
1472
1473                if (sym)
1474                        sym->flags &= ~SYMBOL_CHANGED;
1475
1476                if ((view_mode == SPLIT_VIEW)
1477                    && !(child->flags & MENU_ROOT) && (tree == tree1))
1478                        continue;
1479
1480                if ((view_mode == SPLIT_VIEW) && (child->flags & MENU_ROOT)
1481                    && (tree == tree2))
1482                        continue;
1483
1484                if (menu_is_visible(child) || show_all)
1485                        place_node(child, fill_row(child));
1486#ifdef DEBUG
1487                printf("%*c%s: ", indent, ' ', menu_get_prompt(child));
1488                printf("%s", child->flags & MENU_ROOT ? "rootmenu | " : "");
1489                dbg_print_ptype(ptype);
1490                printf(" | ");
1491                if (sym) {
1492                        dbg_print_stype(sym->type);
1493                        printf(" | ");
1494                        dbg_print_flags(sym->flags);
1495                        printf("\n");
1496                } else
1497                        printf("\n");
1498#endif
1499                if ((view_mode != FULL_VIEW) && (ptype == P_MENU)
1500                    && (tree == tree2))
1501                        continue;
1502/*
1503                if (((menu != &rootmenu) && !(menu->flags & MENU_ROOT))
1504                    || (view_mode == FULL_VIEW)
1505                    || (view_mode == SPLIT_VIEW))*/
1506                if (((view_mode == SINGLE_VIEW) && (menu->flags & MENU_ROOT))
1507                    || (view_mode == FULL_VIEW)
1508                    || (view_mode == SPLIT_VIEW)) {
1509                        indent++;
1510                        display_tree(child);
1511                        indent--;
1512                }
1513        }
1514}
1515
1516/* Display a part of the tree starting at current node (single/split view) */
1517static void display_tree_part(void)
1518{
1519        if (tree2)
1520                gtk_tree_store_clear(tree2);
1521        if (view_mode == SINGLE_VIEW)
1522                display_tree(current);
1523        else if (view_mode == SPLIT_VIEW)
1524                display_tree(browsed);
1525        gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w));
1526}
1527
1528/* Display the list in the left frame (split view) */
1529static void display_list(void)
1530{
1531        if (tree1)
1532                gtk_tree_store_clear(tree1);
1533
1534        tree = tree1;
1535        display_tree(&rootmenu);
1536        gtk_tree_view_expand_all(GTK_TREE_VIEW(tree1_w));
1537        tree = tree2;
1538}
1539
1540void fixup_rootmenu(struct menu *menu)
1541{
1542        struct menu *child;
1543        static int menu_cnt = 0;
1544
1545        menu->flags |= MENU_ROOT;
1546        for (child = menu->list; child; child = child->next) {
1547                if (child->prompt && child->prompt->type == P_MENU) {
1548                        menu_cnt++;
1549                        fixup_rootmenu(child);
1550                        menu_cnt--;
1551                } else if (!menu_cnt)
1552                        fixup_rootmenu(child);
1553        }
1554}
1555
1556
1557/* Main */
1558int main(int ac, char *av[])
1559{
1560        const char *name;
1561        char *env;
1562        gchar *glade_file;
1563
1564#ifndef LKC_DIRECT_LINK
1565        kconfig_load();
1566#endif
1567
1568        bindtextdomain(PACKAGE, LOCALEDIR);
1569        bind_textdomain_codeset(PACKAGE, "UTF-8");
1570        textdomain(PACKAGE);
1571
1572        /* GTK stuffs */
1573        gtk_set_locale();
1574        gtk_init(&ac, &av);
1575        glade_init();
1576
1577        //add_pixmap_directory (PACKAGE_DATA_DIR "/" PACKAGE "/pixmaps");
1578        //add_pixmap_directory (PACKAGE_SOURCE_DIR "/pixmaps");
1579
1580        /* Determine GUI path */
1581        env = getenv(SRCTREE);
1582        if (env)
1583                glade_file = g_strconcat(env, "/util/kconfig/gconf.glade", NULL);
1584        else if (av[0][0] == '/')
1585                glade_file = g_strconcat(av[0], ".glade", NULL);
1586        else
1587                glade_file = g_strconcat(g_get_current_dir(), "/", av[0], ".glade", NULL);
1588
1589        /* Load the interface and connect signals */
1590        init_main_window(glade_file);
1591        init_tree_model();
1592        init_left_tree();
1593        init_right_tree();
1594
1595        /* Conf stuffs */
1596        if (ac > 1 && av[1][0] == '-') {
1597                switch (av[1][1]) {
1598                case 'a':
1599                        //showAll = 1;
1600                        break;
1601                case 'h':
1602                case '?':
1603                        printf("%s <config>\n", av[0]);
1604                        exit(0);
1605                }
1606                name = av[2];
1607        } else
1608                name = av[1];
1609
1610        conf_parse(name);
1611        fixup_rootmenu(&rootmenu);
1612        conf_read(NULL);
1613
1614        switch (view_mode) {
1615        case SINGLE_VIEW:
1616                display_tree_part();
1617                break;
1618        case SPLIT_VIEW:
1619                display_list();
1620                break;
1621        case FULL_VIEW:
1622                display_tree(&rootmenu);
1623                break;
1624        }
1625
1626        gtk_main();
1627
1628        return 0;
1629}
1630
1631static void conf_changed(void)
1632{
1633        bool changed = conf_get_changed();
1634        gtk_widget_set_sensitive(save_btn, changed);
1635        gtk_widget_set_sensitive(save_menu_item, changed);
1636}
1637
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.