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