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