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#ifdef HAVE_CONFIG_H
   7#  include <config.h>
   8#endif
   9
  10#include <stdlib.h>
  11#include "lkc.h"
  12#include "images.h"
  13
  14#include <glade/glade.h>
  15#include <gtk/gtk.h>
  16#include <glib.h>
  17#include <gdk/gdkkeysyms.h>
  18
  19#include <stdio.h>
  20#include <string.h>
  21#include <strings.h>
  22#include <unistd.h>
  23#include <time.h>
  24
  25//#define DEBUG
  26
  27enum {
  28        SINGLE_VIEW, SPLIT_VIEW, FULL_VIEW
  29};
  30
  31enum {
  32        OPT_NORMAL, OPT_ALL, OPT_PROMPT
  33};
  34
  35static gint view_mode = FULL_VIEW;
  36static gboolean show_name = TRUE;
  37static gboolean show_range = TRUE;
  38static gboolean show_value = TRUE;
  39static gboolean resizeable = FALSE;
  40static int opt_mode = OPT_NORMAL;
  41
  42GtkWidget *main_wnd = NULL;
  43GtkWidget *tree1_w = NULL;      // left  frame
  44GtkWidget *tree2_w = NULL;      // right frame
  45GtkWidget *text_w = NULL;
  46GtkWidget *hpaned = NULL;
  47GtkWidget *vpaned = NULL;
  48GtkWidget *back_btn = NULL;
  49GtkWidget *save_btn = NULL;
  50GtkWidget *save_menu_item = NULL;
  51
  52GtkTextTag *tag1, *tag2;
  53GdkColor color;
  54
  55GtkTreeStore *tree1, *tree2, *tree;
  56GtkTreeModel *model1, *model2;
  57static GtkTreeIter *parents[256];
  58static gint indent;
  59
  60static struct menu *current; // current node for SINGLE view
  61static struct menu *browsed; // browsed node for SPLIT view
  62
  63enum {
  64        COL_OPTION, COL_NAME, COL_NO, COL_MOD, COL_YES, COL_VALUE,
  65        COL_MENU, COL_COLOR, COL_EDIT, COL_PIXBUF,
  66        COL_PIXVIS, COL_BTNVIS, COL_BTNACT, COL_BTNINC, COL_BTNRAD,
  67        COL_NUMBER
  68};
  69
  70static void display_list(void);
  71static void display_tree(struct menu *menu);
  72static void display_tree_part(void);
  73static void update_tree(struct menu *src, GtkTreeIter * dst);
  74static void set_node(GtkTreeIter * node, struct menu *menu, gchar ** row);
  75static gchar **fill_row(struct menu *menu);
  76static void conf_changed(void);
  77
  78/* Helping/Debugging Functions */
  79#ifdef DEBUG
  80static const char *dbg_sym_flags(int val)
  81{
  82        static char buf[256];
  83
  84        bzero(buf, 256);
  85
  86        if (val & SYMBOL_CONST)
  87                strcat(buf, "const/");
  88        if (val & SYMBOL_CHECK)
  89                strcat(buf, "check/");
  90        if (val & SYMBOL_CHOICE)
  91                strcat(buf, "choice/");
  92        if (val & SYMBOL_CHOICEVAL)
  93                strcat(buf, "choiceval/");
  94        if (val & SYMBOL_VALID)
  95                strcat(buf, "valid/");
  96        if (val & SYMBOL_OPTIONAL)
  97                strcat(buf, "optional/");
  98        if (val & SYMBOL_WRITE)
  99                strcat(buf, "write/");
 100        if (val & SYMBOL_CHANGED)
 101                strcat(buf, "changed/");
 102        if (val & SYMBOL_NO_WRITE)
 103                strcat(buf, "no_write/");
 104
 105        buf[strlen(buf) - 1] = '\0';
 106
 107        return buf;
 108}
 109#endif
 110
 111static void replace_button_icon(GladeXML *xml, GdkDrawable *window,
 112                                GtkStyle *style, gchar *btn_name, gchar **xpm)
 113{
 114        GdkPixmap *pixmap;
 115        GdkBitmap *mask;
 116        GtkToolButton *button;
 117        GtkWidget *image;
 118
 119        pixmap = gdk_pixmap_create_from_xpm_d(window, &mask,
 120                                              &style->bg[GTK_STATE_NORMAL],
 121                                              xpm);
 122
 123        button = GTK_TOOL_BUTTON(glade_xml_get_widget(xml, btn_name));
 124        image = gtk_image_new_from_pixmap(pixmap, mask);
 125        gtk_widget_show(image);
 126        gtk_tool_button_set_icon_widget(button, image);
 127}
 128
 129/* Main Window Initialization */
 130static void init_main_window(const gchar *glade_file)
 131{
 132        GladeXML *xml;
 133        GtkWidget *widget;
 134        GtkTextBuffer *txtbuf;
 135        GtkStyle *style;
 136
 137        xml = glade_xml_new(glade_file, "window1", NULL);
 138        if (!xml)
 139                g_error("GUI loading failed !\n");
 140        glade_xml_signal_autoconnect(xml);
 141
 142        main_wnd = glade_xml_get_widget(xml, "window1");
 143        hpaned = glade_xml_get_widget(xml, "hpaned1");
 144        vpaned = glade_xml_get_widget(xml, "vpaned1");
 145        tree1_w = glade_xml_get_widget(xml, "treeview1");
 146        tree2_w = glade_xml_get_widget(xml, "treeview2");
 147        text_w = glade_xml_get_widget(xml, "textview3");
 148
 149        back_btn = glade_xml_get_widget(xml, "button1");
 150        gtk_widget_set_sensitive(back_btn, FALSE);
 151
 152        widget = glade_xml_get_widget(xml, "show_name1");
 153        gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget,
 154                                       show_name);
 155
 156        widget = glade_xml_get_widget(xml, "show_range1");
 157        gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget,
 158                                       show_range);
 159
 160        widget = glade_xml_get_widget(xml, "show_data1");
 161        gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget,
 162                                       show_value);
 163
 164        save_btn = glade_xml_get_widget(xml, "button3");
 165        save_menu_item = glade_xml_get_widget(xml, "save1");
 166        conf_set_changed_callback(conf_changed);
 167
 168        style = gtk_widget_get_style(main_wnd);
 169        widget = glade_xml_get_widget(xml, "toolbar1");
 170
 171        replace_button_icon(xml, main_wnd->window, style,
 172                            "button4", (gchar **) xpm_single_view);
 173        replace_button_icon(xml, main_wnd->window, style,
 174                            "button5", (gchar **) xpm_split_view);
 175        replace_button_icon(xml, main_wnd->window, style,
 176                            "button6", (gchar **) xpm_tree_view);
 177
 178        txtbuf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w));
 179        tag1 = gtk_text_buffer_create_tag(txtbuf, "mytag1",
 180                                          "foreground", "red",
 181                                          "weight", PANGO_WEIGHT_BOLD,
 182                                          NULL);
 183        tag2 = gtk_text_buffer_create_tag(txtbuf, "mytag2",
 184                                          /*"style", PANGO_STYLE_OBLIQUE, */
 185                                          NULL);
 186
 187        gtk_window_set_title(GTK_WINDOW(main_wnd), rootmenu.prompt->text);
 188
 189        gtk_widget_show(main_wnd);
 190}
 191
 192static void init_tree_model(void)
 193{
 194        gint i;
 195
 196        tree = tree2 = gtk_tree_store_new(COL_NUMBER,
 197                                          G_TYPE_STRING, G_TYPE_STRING,
 198                                          G_TYPE_STRING, G_TYPE_STRING,
 199                                          G_TYPE_STRING, G_TYPE_STRING,
 200                                          G_TYPE_POINTER, GDK_TYPE_COLOR,
 201                                          G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF,
 202                                          G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
 203                                          G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
 204                                          G_TYPE_BOOLEAN);
 205        model2 = GTK_TREE_MODEL(tree2);
 206
 207        for (parents[0] = NULL, i = 1; i < 256; i++)
 208                parents[i] = (GtkTreeIter *) g_malloc(sizeof(GtkTreeIter));
 209
 210        tree1 = gtk_tree_store_new(COL_NUMBER,
 211                                   G_TYPE_STRING, G_TYPE_STRING,
 212                                   G_TYPE_STRING, G_TYPE_STRING,
 213                                   G_TYPE_STRING, G_TYPE_STRING,
 214                                   G_TYPE_POINTER, GDK_TYPE_COLOR,
 215                                   G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF,
 216                                   G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
 217                                   G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
 218                                   G_TYPE_BOOLEAN);
 219        model1 = GTK_TREE_MODEL(tree1);
 220}
 221
 222static void init_left_tree(void)
 223{
 224        GtkTreeView *view = GTK_TREE_VIEW(tree1_w);
 225        GtkCellRenderer *renderer;
 226        GtkTreeSelection *sel;
 227        GtkTreeViewColumn *column;
 228
 229        gtk_tree_view_set_model(view, model1);
 230        gtk_tree_view_set_headers_visible(view, TRUE);
 231        gtk_tree_view_set_rules_hint(view, TRUE);
 232
 233        column = gtk_tree_view_column_new();
 234        gtk_tree_view_append_column(view, column);
 235        gtk_tree_view_column_set_title(column, "Options");
 236
 237        renderer = gtk_cell_renderer_toggle_new();
 238        gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
 239                                        renderer, FALSE);
 240        gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
 241                                            renderer,
 242                                            "active", COL_BTNACT,
 243                                            "inconsistent", COL_BTNINC,
 244                                            "visible", COL_BTNVIS,
 245                                            "radio", COL_BTNRAD, NULL);
 246        renderer = gtk_cell_renderer_text_new();
 247        gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
 248                                        renderer, FALSE);
 249        gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
 250                                            renderer,
 251                                            "text", COL_OPTION,
 252                                            "foreground-gdk",
 253                                            COL_COLOR, NULL);
 254
 255        sel = gtk_tree_view_get_selection(view);
 256        gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
 257        gtk_widget_realize(tree1_w);
 258}
 259
 260static void renderer_edited(GtkCellRendererText * cell,
 261                            const gchar * path_string,
 262                            const gchar * new_text, gpointer user_data);
 263
 264static void init_right_tree(void)
 265{
 266        GtkTreeView *view = GTK_TREE_VIEW(tree2_w);
 267        GtkCellRenderer *renderer;
 268        GtkTreeSelection *sel;
 269        GtkTreeViewColumn *column;
 270        gint i;
 271
 272        gtk_tree_view_set_model(view, model2);
 273        gtk_tree_view_set_headers_visible(view, TRUE);
 274        gtk_tree_view_set_rules_hint(view, TRUE);
 275
 276        column = gtk_tree_view_column_new();
 277        gtk_tree_view_append_column(view, column);
 278        gtk_tree_view_column_set_title(column, "Options");
 279
 280        renderer = gtk_cell_renderer_pixbuf_new();
 281        gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
 282                                        renderer, FALSE);
 283        gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
 284                                            renderer,
 285                                            "pixbuf", COL_PIXBUF,
 286                                            "visible", COL_PIXVIS, NULL);
 287        renderer = gtk_cell_renderer_toggle_new();
 288        gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
 289                                        renderer, FALSE);
 290        gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
 291                                            renderer,
 292                                            "active", COL_BTNACT,
 293                                            "inconsistent", COL_BTNINC,
 294                                            "visible", COL_BTNVIS,
 295                                            "radio", COL_BTNRAD, NULL);
 296        renderer = gtk_cell_renderer_text_new();
 297        gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
 298                                        renderer, FALSE);
 299        gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
 300                                            renderer,
 301                                            "text", COL_OPTION,
 302                                            "foreground-gdk",
 303                                            COL_COLOR, NULL);
 304
 305        renderer = gtk_cell_renderer_text_new();
 306        gtk_tree_view_insert_column_with_attributes(view, -1,
 307                                                    "Name", renderer,
 308                                                    "text", COL_NAME,
 309                                                    "foreground-gdk",
 310                                                    COL_COLOR, NULL);
 311        renderer = gtk_cell_renderer_text_new();
 312        gtk_tree_view_insert_column_with_attributes(view, -1,
 313                                                    "N", renderer,
 314                                                    "text", COL_NO,
 315                                                    "foreground-gdk",
 316                                                    COL_COLOR, NULL);
 317        renderer = gtk_cell_renderer_text_new();
 318        gtk_tree_view_insert_column_with_attributes(view, -1,
 319                                                    "M", renderer,
 320                                                    "text", COL_MOD,
 321                                                    "foreground-gdk",
 322                                                    COL_COLOR, NULL);
 323        renderer = gtk_cell_renderer_text_new();
 324        gtk_tree_view_insert_column_with_attributes(view, -1,
 325                                                    "Y", renderer,
 326                                                    "text", COL_YES,
 327                                                    "foreground-gdk",
 328                                                    COL_COLOR, NULL);
 329        renderer = gtk_cell_renderer_text_new();
 330        gtk_tree_view_insert_column_with_attributes(view, -1,
 331                                                    "Value", renderer,
 332                                                    "text", COL_VALUE,
 333                                                    "editable",
 334                                                    COL_EDIT,
 335                                                    "foreground-gdk",
 336                                                    COL_COLOR, NULL);
 337        g_signal_connect(G_OBJECT(renderer), "edited",
 338                         G_CALLBACK(renderer_edited), NULL);
 339
 340        column = gtk_tree_view_get_column(view, COL_NAME);
 341        gtk_tree_view_column_set_visible(column, show_name);
 342        column = gtk_tree_view_get_column(view, COL_NO);
 343        gtk_tree_view_column_set_visible(column, show_range);
 344        column = gtk_tree_view_get_column(view, COL_MOD);
 345        gtk_tree_view_column_set_visible(column, show_range);
 346        column = gtk_tree_view_get_column(view, COL_YES);
 347        gtk_tree_view_column_set_visible(column, show_range);
 348        column = gtk_tree_view_get_column(view, COL_VALUE);
 349        gtk_tree_view_column_set_visible(column, show_value);
 350
 351        if (resizeable) {
 352                for (i = 0; i < COL_VALUE; i++) {
 353                        column = gtk_tree_view_get_column(view, i);
 354                        gtk_tree_view_column_set_resizable(column, TRUE);
 355                }
 356        }
 357
 358        sel = gtk_tree_view_get_selection(view);
 359        gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
 360}
 361
 362
 363/* Utility Functions */
 364
 365
 366static void text_insert_help(struct menu *menu)
 367{
 368        GtkTextBuffer *buffer;
 369        GtkTextIter start, end;
 370        const char *prompt = menu_get_prompt(menu);
 371        struct gstr help = str_new();
 372
 373        menu_get_ext_help(menu, &help);
 374
 375        buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w));
 376        gtk_text_buffer_get_bounds(buffer, &start, &end);
 377        gtk_text_buffer_delete(buffer, &start, &end);
 378        gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_w), 15);
 379
 380        gtk_text_buffer_get_end_iter(buffer, &end);
 381        gtk_text_buffer_insert_with_tags(buffer, &end, prompt, -1, tag1,
 382                                         NULL);
 383        gtk_text_buffer_insert_at_cursor(buffer, "\n\n", 2);
 384        gtk_text_buffer_get_end_iter(buffer, &end);
 385        gtk_text_buffer_insert_with_tags(buffer, &end, str_get(&help), -1, tag2,
 386                                         NULL);
 387        str_free(&help);
 388}
 389
 390
 391static void text_insert_msg(const char *title, const char *message)
 392{
 393        GtkTextBuffer *buffer;
 394        GtkTextIter start, end;
 395        const char *msg = message;
 396
 397        buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w));
 398        gtk_text_buffer_get_bounds(buffer, &start, &end);
 399        gtk_text_buffer_delete(buffer, &start, &end);
 400        gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_w), 15);
 401
 402        gtk_text_buffer_get_end_iter(buffer, &end);
 403        gtk_text_buffer_insert_with_tags(buffer, &end, title, -1, tag1,
 404                                         NULL);
 405        gtk_text_buffer_insert_at_cursor(buffer, "\n\n", 2);
 406        gtk_text_buffer_get_end_iter(buffer, &end);
 407        gtk_text_buffer_insert_with_tags(buffer, &end, msg, -1, tag2,
 408                                         NULL);
 409}
 410
 411
 412/* Main Windows Callbacks */
 413
 414void on_save_activate(GtkMenuItem * menuitem, gpointer user_data);
 415gboolean on_window1_delete_event(GtkWidget * widget, GdkEvent * event,
 416                                 gpointer user_data)
 417{
 418        GtkWidget *dialog, *label;
 419        gint result;
 420
 421        if (!conf_get_changed())
 422                return FALSE;
 423
 424        dialog = gtk_dialog_new_with_buttons("Warning !",
 425                                             GTK_WINDOW(main_wnd),
 426                                             (GtkDialogFlags)
 427                                             (GTK_DIALOG_MODAL |
 428                                              GTK_DIALOG_DESTROY_WITH_PARENT),
 429                                             GTK_STOCK_OK,
 430                                             GTK_RESPONSE_YES,
 431                                             GTK_STOCK_NO,
 432                                             GTK_RESPONSE_NO,
 433                                             GTK_STOCK_CANCEL,
 434                                             GTK_RESPONSE_CANCEL, NULL);
 435        gtk_dialog_set_default_response(GTK_DIALOG(dialog),
 436                                        GTK_RESPONSE_CANCEL);
 437
 438        label = gtk_label_new("\nSave configuration ?\n");
 439        gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), label);
 440        gtk_widget_show(label);
 441
 442        result = gtk_dialog_run(GTK_DIALOG(dialog));
 443        switch (result) {
 444        case GTK_RESPONSE_YES:
 445                on_save_activate(NULL, NULL);
 446                return FALSE;
 447        case GTK_RESPONSE_NO:
 448                return FALSE;
 449        case GTK_RESPONSE_CANCEL:
 450        case GTK_RESPONSE_DELETE_EVENT:
 451        default:
 452                gtk_widget_destroy(dialog);
 453                return TRUE;
 454        }
 455
 456        return FALSE;
 457}
 458
 459
 460void on_window1_destroy(GtkObject * object, gpointer user_data)
 461{
 462        gtk_main_quit();
 463}
 464
 465
 466void
 467on_window1_size_request(GtkWidget * widget,
 468                        GtkRequisition * requisition, gpointer user_data)
 469{
 470        static gint old_h;
 471        gint w, h;
 472
 473        if (widget->window == NULL)
 474                gtk_window_get_default_size(GTK_WINDOW(main_wnd), &w, &h);
 475        else
 476                gdk_window_get_size(widget->window, &w, &h);
 477
 478        if (h == old_h)
 479                return;
 480        old_h = h;
 481
 482        gtk_paned_set_position(GTK_PANED(vpaned), 2 * h / 3);
 483}
 484
 485
 486/* Menu & Toolbar Callbacks */
 487
 488
 489static void
 490load_filename(GtkFileSelection * file_selector, gpointer user_data)
 491{
 492        const gchar *fn;
 493
 494        fn = gtk_file_selection_get_filename(GTK_FILE_SELECTION
 495                                             (user_data));
 496
 497        if (conf_read(fn))
 498                text_insert_msg("Error", "Unable to load configuration !");
 499        else
 500                display_tree(&rootmenu);
 501}
 502
 503void on_load1_activate(GtkMenuItem * menuitem, gpointer user_data)
 504{
 505        GtkWidget *fs;
 506
 507        fs = gtk_file_selection_new("Load file...");
 508        g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs)->ok_button),
 509                         "clicked",
 510                         G_CALLBACK(load_filename), (gpointer) fs);
 511        g_signal_connect_swapped(GTK_OBJECT
 512                                 (GTK_FILE_SELECTION(fs)->ok_button),
 513                                 "clicked", G_CALLBACK(gtk_widget_destroy),
 514                                 (gpointer) fs);
 515        g_signal_connect_swapped(GTK_OBJECT
 516                                 (GTK_FILE_SELECTION(fs)->cancel_button),
 517                                 "clicked", G_CALLBACK(gtk_widget_destroy),
 518                                 (gpointer) fs);
 519        gtk_widget_show(fs);
 520}
 521
 522
 523void on_save_activate(GtkMenuItem * menuitem, gpointer user_data)
 524{
 525        if (conf_write(NULL))
 526                text_insert_msg("Error", "Unable to save configuration !");
 527        conf_write_autoconf(0);
 528}
 529
 530
 531static void
 532store_filename(GtkFileSelection * file_selector, gpointer user_data)
 533{
 534        const gchar *fn;
 535
 536        fn = gtk_file_selection_get_filename(GTK_FILE_SELECTION
 537                                             (user_data));
 538
 539        if (conf_write(fn))
 540                text_insert_msg("Error", "Unable to save configuration !");
 541
 542        gtk_widget_destroy(GTK_WIDGET(user_data));
 543}
 544
 545void on_save_as1_activate(GtkMenuItem * menuitem, gpointer user_data)
 546{
 547        GtkWidget *fs;
 548
 549        fs = gtk_file_selection_new("Save file as...");
 550        g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs)->ok_button),
 551                         "clicked",
 552                         G_CALLBACK(store_filename), (gpointer) fs);
 553        g_signal_connect_swapped(GTK_OBJECT
 554                                 (GTK_FILE_SELECTION(fs)->ok_button),
 555                                 "clicked", G_CALLBACK(gtk_widget_destroy),
 556                                 (gpointer) fs);
 557        g_signal_connect_swapped(GTK_OBJECT
 558                                 (GTK_FILE_SELECTION(fs)->cancel_button),
 559                                 "clicked", G_CALLBACK(gtk_widget_destroy),
 560                                 (gpointer) fs);
 561        gtk_widget_show(fs);
 562}
 563
 564
 565void on_quit1_activate(GtkMenuItem * menuitem, gpointer user_data)
 566{
 567        if (!on_window1_delete_event(NULL, NULL, NULL))
 568                gtk_widget_destroy(GTK_WIDGET(main_wnd));
 569}
 570
 571
 572void on_show_name1_activate(GtkMenuItem * menuitem, gpointer user_data)
 573{
 574        GtkTreeViewColumn *col;
 575
 576        show_name = GTK_CHECK_MENU_ITEM(menuitem)->active;
 577        col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_NAME);
 578        if (col)
 579                gtk_tree_view_column_set_visible(col, show_name);
 580}
 581
 582
 583void on_show_range1_activate(GtkMenuItem * menuitem, gpointer user_data)
 584{
 585        GtkTreeViewColumn *col;
 586
 587        show_range = GTK_CHECK_MENU_ITEM(menuitem)->active;
 588        col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_NO);
 589        if (col)
 590                gtk_tree_view_column_set_visible(col, show_range);
 591        col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_MOD);
 592        if (col)
 593                gtk_tree_view_column_set_visible(col, show_range);
 594        col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_YES);
 595        if (col)
 596                gtk_tree_view_column_set_visible(col, show_range);
 597
 598}
 599
 600
 601void on_show_data1_activate(GtkMenuItem * menuitem, gpointer user_data)
 602{
 603        GtkTreeViewColumn *col;
 604
 605        show_value = GTK_CHECK_MENU_ITEM(menuitem)->active;
 606        col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_VALUE);
 607        if (col)
 608                gtk_tree_view_column_set_visible(col, show_value);
 609}
 610
 611
 612void
 613on_set_option_mode1_activate(GtkMenuItem *menuitem, gpointer user_data)
 614{
 615        opt_mode = OPT_NORMAL;
 616        gtk_tree_store_clear(tree2);
 617        display_tree(&rootmenu);        /* instead of update_tree to speed-up */
 618}
 619
 620
 621void
 622on_set_option_mode2_activate(GtkMenuItem *menuitem, gpointer user_data)
 623{
 624        opt_mode = OPT_ALL;
 625        gtk_tree_store_clear(tree2);
 626        display_tree(&rootmenu);        /* instead of update_tree to speed-up */
 627}
 628
 629
 630void
 631on_set_option_mode3_activate(GtkMenuItem *menuitem, gpointer user_data)
 632{
 633        opt_mode = OPT_PROMPT;
 634        gtk_tree_store_clear(tree2);
 635        display_tree(&rootmenu);        /* instead of update_tree to speed-up */
 636}
 637
 638
 639void on_introduction1_activate(GtkMenuItem * menuitem, gpointer user_data)
 640{
 641        GtkWidget *dialog;
 642        const gchar *intro_text =
 643            "Welcome to gkc, the GTK+ graphical configuration tool\n"
 644            "For each option, a blank box indicates the feature is disabled, a\n"
 645            "check indicates it is enabled, and a dot indicates that it is to\n"
 646            "be compiled as a module.  Clicking on the box will cycle through the three states.\n"
 647            "\n"
 648            "If you do not see an option (e.g., a device driver) that you\n"
 649            "believe should be present, try turning on Show All Options\n"
 650            "under the Options menu.\n"
 651            "Although there is no cross reference yet to help you figure out\n"
 652            "what other options must be enabled to support the option you\n"
 653            "are interested in, you can still view the help of a grayed-out\n"
 654            "option.\n"
 655            "\n"
 656            "Toggling Show Debug Info under the Options menu will show \n"
 657            "the dependencies, which you can then match by examining other options.";
 658
 659        dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
 660                                        GTK_DIALOG_DESTROY_WITH_PARENT,
 661                                        GTK_MESSAGE_INFO,
 662                                        GTK_BUTTONS_CLOSE, "%s", intro_text);
 663        g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
 664                                 G_CALLBACK(gtk_widget_destroy),
 665                                 GTK_OBJECT(dialog));
 666        gtk_widget_show_all(dialog);
 667}
 668
 669
 670void on_about1_activate(GtkMenuItem * menuitem, gpointer user_data)
 671{
 672        GtkWidget *dialog;
 673        const gchar *about_text =
 674            "gkc is copyright (c) 2002 Romain Lievin <roms@lpg.ticalc.org>.\n"
 675              "Based on the source code from Roman Zippel.\n";
 676
 677        dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
 678                                        GTK_DIALOG_DESTROY_WITH_PARENT,
 679                                        GTK_MESSAGE_INFO,
 680                                        GTK_BUTTONS_CLOSE, "%s", about_text);
 681        g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
 682                                 G_CALLBACK(gtk_widget_destroy),
 683                                 GTK_OBJECT(dialog));
 684        gtk_widget_show_all(dialog);
 685}
 686
 687
 688void on_license1_activate(GtkMenuItem * menuitem, gpointer user_data)
 689{
 690        GtkWidget *dialog;
 691        const gchar *license_text =
 692            "gkc is released under the terms of the GNU GPL v2.\n"
 693              "For more information, please see the source code or\n"
 694              "visit http://www.fsf.org/licenses/licenses.html\n";
 695
 696        dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
 697                                        GTK_DIALOG_DESTROY_WITH_PARENT,
 698                                        GTK_MESSAGE_INFO,
 699                                        GTK_BUTTONS_CLOSE, "%s", license_text);
 700        g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
 701                                 G_CALLBACK(gtk_widget_destroy),
 702                                 GTK_OBJECT(dialog));
 703        gtk_widget_show_all(dialog);
 704}
 705
 706
 707void on_back_clicked(GtkButton * button, gpointer user_data)
 708{
 709        enum prop_type ptype;
 710
 711        current = current->parent;
 712        ptype = current->prompt ? current->prompt->type : P_UNKNOWN;
 713        if (ptype != P_MENU)
 714                current = current->parent;
 715        display_tree_part();
 716
 717        if (current == &rootmenu)
 718                gtk_widget_set_sensitive(back_btn, FALSE);
 719}
 720
 721
 722void on_load_clicked(GtkButton * button, gpointer user_data)
 723{
 724        on_load1_activate(NULL, user_data);
 725}
 726
 727
 728void on_single_clicked(GtkButton * button, gpointer user_data)
 729{
 730        view_mode = SINGLE_VIEW;
 731        gtk_widget_hide(tree1_w);
 732        current = &rootmenu;
 733        display_tree_part();
 734}
 735
 736
 737void on_split_clicked(GtkButton * button, gpointer user_data)
 738{
 739        gint w, h;
 740        view_mode = SPLIT_VIEW;
 741        gtk_widget_show(tree1_w);
 742        gtk_window_get_default_size(GTK_WINDOW(main_wnd), &w, &h);
 743        gtk_paned_set_position(GTK_PANED(hpaned), w / 2);
 744        if (tree2)
 745                gtk_tree_store_clear(tree2);
 746        display_list();
 747
 748        /* Disable back btn, like in full mode. */
 749        gtk_widget_set_sensitive(back_btn, FALSE);
 750}
 751
 752
 753void on_full_clicked(GtkButton * button, gpointer user_data)
 754{
 755        view_mode = FULL_VIEW;
 756        gtk_widget_hide(tree1_w);
 757        if (tree2)
 758                gtk_tree_store_clear(tree2);
 759        display_tree(&rootmenu);
 760        gtk_widget_set_sensitive(back_btn, FALSE);
 761}
 762
 763
 764void on_collapse_clicked(GtkButton * button, gpointer user_data)
 765{
 766        gtk_tree_view_collapse_all(GTK_TREE_VIEW(tree2_w));
 767}
 768
 769
 770void on_expand_clicked(GtkButton * button, gpointer user_data)
 771{
 772        gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w));
 773}
 774
 775
 776/* CTree Callbacks */
 777
 778/* Change hex/int/string value in the cell */
 779static void renderer_edited(GtkCellRendererText * cell,
 780                            const gchar * path_string,
 781                            const gchar * new_text, gpointer user_data)
 782{
 783        GtkTreePath *path = gtk_tree_path_new_from_string(path_string);
 784        GtkTreeIter iter;
 785        const char *old_def, *new_def;
 786        struct menu *menu;
 787        struct symbol *sym;
 788
 789        if (!gtk_tree_model_get_iter(model2, &iter, path))
 790                return;
 791
 792        gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
 793        sym = menu->sym;
 794
 795        gtk_tree_model_get(model2, &iter, COL_VALUE, &old_def, -1);
 796        new_def = new_text;
 797
 798        sym_set_string_value(sym, new_def);
 799
 800        update_tree(&rootmenu, NULL);
 801
 802        gtk_tree_path_free(path);
 803}
 804
 805/* Change the value of a symbol and update the tree */
 806static void change_sym_value(struct menu *menu, gint col)
 807{
 808        struct symbol *sym = menu->sym;
 809        tristate newval;
 810
 811        if (!sym)
 812                return;
 813
 814        if (col == COL_NO)
 815                newval = no;
 816        else if (col == COL_MOD)
 817                newval = mod;
 818        else if (col == COL_YES)
 819                newval = yes;
 820        else
 821                return;
 822
 823        switch (sym_get_type(sym)) {
 824        case S_BOOLEAN:
 825        case S_TRISTATE:
 826                if (!sym_tristate_within_range(sym, newval))
 827                        newval = yes;
 828                sym_set_tristate_value(sym, newval);
 829                if (view_mode == FULL_VIEW)
 830                        update_tree(&rootmenu, NULL);
 831                else if (view_mode == SPLIT_VIEW) {
 832                        update_tree(browsed, NULL);
 833                        display_list();
 834                }
 835                else if (view_mode == SINGLE_VIEW)
 836                        display_tree_part();    //fixme: keep exp/coll
 837                break;
 838        case S_INT:
 839        case S_HEX:
 840        case S_STRING:
 841        default:
 842                break;
 843        }
 844}
 845
 846static void toggle_sym_value(struct menu *menu)
 847{
 848        if (!menu->sym)
 849                return;
 850
 851        sym_toggle_tristate_value(menu->sym);
 852        if (view_mode == FULL_VIEW)
 853                update_tree(&rootmenu, NULL);
 854        else if (view_mode == SPLIT_VIEW) {
 855                update_tree(browsed, NULL);
 856                display_list();
 857        }
 858        else if (view_mode == SINGLE_VIEW)
 859                display_tree_part();    //fixme: keep exp/coll
 860}
 861
 862static gint column2index(GtkTreeViewColumn * column)
 863{
 864        gint i;
 865
 866        for (i = 0; i < COL_NUMBER; i++) {
 867                GtkTreeViewColumn *col;
 868
 869                col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), i);
 870                if (col == column)
 871                        return i;
 872        }
 873
 874        return -1;
 875}
 876
 877
 878/* User click: update choice (full) or goes down (single) */
 879gboolean
 880on_treeview2_button_press_event(GtkWidget * widget,
 881                                GdkEventButton * event, gpointer user_data)
 882{
 883        GtkTreeView *view = GTK_TREE_VIEW(widget);
 884        GtkTreePath *path;
 885        GtkTreeViewColumn *column;
 886        GtkTreeIter iter;
 887        struct menu *menu;
 888        gint col;
 889
 890#if GTK_CHECK_VERSION(2,1,4) // bug in ctree with earlier version of GTK
 891        gint tx = (gint) event->x;
 892        gint ty = (gint) event->y;
 893        gint cx, cy;
 894
 895        gtk_tree_view_get_path_at_pos(view, tx, ty, &path, &column, &cx,
 896                                      &cy);
 897#else
 898        gtk_tree_view_get_cursor(view, &path, &column);
 899#endif
 900        if (path == NULL)
 901                return FALSE;
 902
 903        if (!gtk_tree_model_get_iter(model2, &iter, path))
 904                return FALSE;
 905        gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
 906
 907        col = column2index(column);
 908        if (event->type == GDK_2BUTTON_PRESS) {
 909                enum prop_type ptype;
 910                ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
 911
 912                if (ptype == P_MENU && view_mode != FULL_VIEW && col == COL_OPTION) {
 913                        // goes down into menu
 914                        current = menu;
 915                        display_tree_part();
 916                        gtk_widget_set_sensitive(back_btn, TRUE);
 917                } else if (col == COL_OPTION) {
 918                        toggle_sym_value(menu);
 919                        gtk_tree_view_expand_row(view, path, TRUE);
 920                }
 921        } else {
 922                if (col == COL_VALUE) {
 923                        toggle_sym_value(menu);
 924                        gtk_tree_view_expand_row(view, path, TRUE);
 925                } else if (col == COL_NO || col == COL_MOD
 926                           || col == COL_YES) {
 927                        change_sym_value(menu, col);
 928                        gtk_tree_view_expand_row(view, path, TRUE);
 929                }
 930        }
 931
 932        return FALSE;
 933}
 934
 935/* Key pressed: update choice */
 936gboolean
 937on_treeview2_key_press_event(GtkWidget * widget,
 938                             GdkEventKey * event, gpointer user_data)
 939{
 940        GtkTreeView *view = GTK_TREE_VIEW(widget);
 941        GtkTreePath *path;
 942        GtkTreeViewColumn *column;
 943        GtkTreeIter iter;
 944        struct menu *menu;
 945        gint col;
 946
 947        gtk_tree_view_get_cursor(view, &path, &column);
 948        if (path == NULL)
 949                return FALSE;
 950
 951        if (event->keyval == GDK_space) {
 952                if (gtk_tree_view_row_expanded(view, path))
 953                        gtk_tree_view_collapse_row(view, path);
 954                else
 955                        gtk_tree_view_expand_row(view, path, FALSE);
 956                return TRUE;
 957        }
 958        if (event->keyval == GDK_KP_Enter) {
 959        }
 960        if (widget == tree1_w)
 961                return FALSE;
 962
 963        gtk_tree_model_get_iter(model2, &iter, path);
 964        gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
 965
 966        if (!strcasecmp(event->string, "n"))
 967                col = COL_NO;
 968        else if (!strcasecmp(event->string, "m"))
 969                col = COL_MOD;
 970        else if (!strcasecmp(event->string, "y"))
 971                col = COL_YES;
 972        else
 973                col = -1;
 974        change_sym_value(menu, col);
 975
 976        return FALSE;
 977}
 978
 979
 980/* Row selection changed: update help */
 981void
 982on_treeview2_cursor_changed(GtkTreeView * treeview, gpointer user_data)
 983{
 984        GtkTreeSelection *selection;
 985        GtkTreeIter iter;
 986        struct menu *menu;
 987
 988        selection = gtk_tree_view_get_selection(treeview);
 989        if (gtk_tree_selection_get_selected(selection, &model2, &iter)) {
 990                gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
 991                text_insert_help(menu);
 992        }
 993}
 994
 995
 996/* User click: display sub-tree in the right frame. */
 997gboolean
 998on_treeview1_button_press_event(GtkWidget * widget,
 999                                GdkEventButton * event, gpointer user_data)
1000{
1001        GtkTreeView *view = GTK_TREE_VIEW(widget);
1002        GtkTreePath *path;
1003        GtkTreeViewColumn *column;
1004        GtkTreeIter iter;
1005        struct menu *menu;
1006
1007        gint tx = (gint) event->x;
1008        gint ty = (gint) event->y;
1009        gint cx, cy;
1010
1011        gtk_tree_view_get_path_at_pos(view, tx, ty, &path, &column, &cx,
1012                                      &cy);
1013        if (path == NULL)
1014                return FALSE;
1015
1016        gtk_tree_model_get_iter(model1, &iter, path);
1017        gtk_tree_model_get(model1, &iter, COL_MENU, &menu, -1);
1018
1019        if (event->type == GDK_2BUTTON_PRESS) {
1020                toggle_sym_value(menu);
1021                current = menu;
1022                display_tree_part();
1023        } else {
1024                browsed = menu;
1025                display_tree_part();
1026        }
1027
1028        gtk_widget_realize(tree2_w);
1029        gtk_tree_view_set_cursor(view, path, NULL, FALSE);
1030        gtk_widget_grab_focus(tree2_w);
1031
1032        return FALSE;
1033}
1034
1035
1036/* Fill a row of strings */
1037static gchar **fill_row(struct menu *menu)
1038{
1039        static gchar *row[COL_NUMBER];
1040        struct symbol *sym = menu->sym;
1041        const char *def;
1042        int stype;
1043        tristate val;
1044        enum prop_type ptype;
1045        int i;
1046
1047        for (i = COL_OPTION; i <= COL_COLOR; i++)
1048                g_free(row[i]);
1049        bzero(row, sizeof(row));
1050
1051        row[COL_OPTION] =
1052            g_strdup_printf("%s %s", menu_get_prompt(menu),
1053                            sym && !sym_has_value(sym) ? "(NEW)" : "");
1054
1055        if (opt_mode == OPT_ALL && !menu_is_visible(menu))
1056                row[COL_COLOR] = g_strdup("DarkGray");
1057        else if (opt_mode == OPT_PROMPT &&
1058                        menu_has_prompt(menu) && !menu_is_visible(menu))
1059                row[COL_COLOR] = g_strdup("DarkGray");
1060        else
1061                row[COL_COLOR] = g_strdup("Black");
1062
1063        ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
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        //add_pixmap_directory (PACKAGE_DATA_DIR "/" PACKAGE "/pixmaps");
1456        //add_pixmap_directory (PACKAGE_SOURCE_DIR "/pixmaps");
1457
1458        /* Determine GUI path */
1459        env = getenv(SRCTREE);
1460        if (env)
1461                glade_file = g_strconcat(env, "/scripts/kconfig/gconf.glade", NULL);
1462        else if (av[0][0] == '/')
1463                glade_file = g_strconcat(av[0], ".glade", NULL);
1464        else
1465                glade_file = g_strconcat(g_get_current_dir(), "/", av[0], ".glade", NULL);
1466
1467        /* Conf stuffs */
1468        if (ac > 1 && av[1][0] == '-') {
1469                switch (av[1][1]) {
1470                case 'a':
1471                        //showAll = 1;
1472                        break;
1473                case 's':
1474                        conf_set_message_callback(NULL);
1475                        break;
1476                case 'h':
1477                case '?':
1478                        printf("%s [-s] <config>\n", av[0]);
1479                        exit(0);
1480                }
1481                name = av[2];
1482        } else
1483                name = av[1];
1484
1485        conf_parse(name);
1486        fixup_rootmenu(&rootmenu);
1487        conf_read(NULL);
1488
1489        /* Load the interface and connect signals */
1490        init_main_window(glade_file);
1491        init_tree_model();
1492        init_left_tree();
1493        init_right_tree();
1494
1495        switch (view_mode) {
1496        case SINGLE_VIEW:
1497                display_tree_part();
1498                break;
1499        case SPLIT_VIEW:
1500                display_list();
1501                break;
1502        case FULL_VIEW:
1503                display_tree(&rootmenu);
1504                break;
1505        }
1506
1507        gtk_main();
1508
1509        return 0;
1510}
1511
1512static void conf_changed(void)
1513{
1514        bool changed = conf_get_changed();
1515        gtk_widget_set_sensitive(save_btn, changed);
1516        gtk_widget_set_sensitive(save_menu_item, changed);
1517}
1518