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