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