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