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