Root/scripts/kconfig/gconf.c

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

Archive Download this file



interactive