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