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