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