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