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