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