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