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