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