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