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