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