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