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