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