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