source: MondoRescue/branches/stable/mindi-busybox/scripts/kconfig/gconf.c @ 1770

Last change on this file since 1770 was 1765, checked in by Bruno Cornec, 12 years ago

Update to busybox 1.7.2

  • Property svn:eol-style set to native
File size: 40.6 KB
Line 
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
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
87    memset(buf, 0, 256);
88
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
115    memset(buf, 0, 256);
116
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
158    memset(buf, 0, 256);
159
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
278    sprintf(title, _("BusyBox %s Configuration"),
279        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 = _(
744        "Welcome to gkc, the GTK+ graphical busybox configuration tool\n"
745        "for Linux.\n"
746        "For each option, a blank box indicates the feature is disabled, a\n"
747        "check indicates it is enabled, and a dot indicates that it is to\n"
748        "be compiled as a module.  Clicking on the box will cycle through the three states.\n"
749        "\n"
750        "If you do not see an option (e.g., a device driver) that you\n"
751        "believe should be present, try turning on Show All Options\n"
752        "under the Options menu.\n"
753        "Although there is no cross reference yet to help you figure out\n"
754        "what other options must be enabled to support the option you\n"
755        "are interested in, you can still view the help of a grayed-out\n"
756        "option.\n"
757        "\n"
758        "Toggling Show Debug Info under the Options menu will show\n"
759        "the dependencies, which you can then match by examining other options.");
760
761    dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
762                    GTK_DIALOG_DESTROY_WITH_PARENT,
763                    GTK_MESSAGE_INFO,
764                    GTK_BUTTONS_CLOSE, intro_text);
765    g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
766                 G_CALLBACK(gtk_widget_destroy),
767                 GTK_OBJECT(dialog));
768    gtk_widget_show_all(dialog);
769}
770
771
772void on_about1_activate(GtkMenuItem * menuitem, gpointer user_data)
773{
774    GtkWidget *dialog;
775    const gchar *about_text =
776        _("gkc is copyright (c) 2002 Romain Lievin <roms@lpg.ticalc.org>.\n"
777          "Based on the source code from Roman Zippel.\n");
778
779    dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
780                    GTK_DIALOG_DESTROY_WITH_PARENT,
781                    GTK_MESSAGE_INFO,
782                    GTK_BUTTONS_CLOSE, about_text);
783    g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
784                 G_CALLBACK(gtk_widget_destroy),
785                 GTK_OBJECT(dialog));
786    gtk_widget_show_all(dialog);
787}
788
789
790void on_license1_activate(GtkMenuItem * menuitem, gpointer user_data)
791{
792    GtkWidget *dialog;
793    const gchar *license_text =
794        _("gkc is released under the terms of the GNU GPL v2.\n"
795          "For more information, please see the source code or\n"
796          "visit http://www.fsf.org/licenses/licenses.html\n");
797
798    dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
799                    GTK_DIALOG_DESTROY_WITH_PARENT,
800                    GTK_MESSAGE_INFO,
801                    GTK_BUTTONS_CLOSE, license_text);
802    g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
803                 G_CALLBACK(gtk_widget_destroy),
804                 GTK_OBJECT(dialog));
805    gtk_widget_show_all(dialog);
806}
807
808
809void on_back_clicked(GtkButton * button, gpointer user_data)
810{
811    enum prop_type ptype;
812
813    current = current->parent;
814    ptype = current->prompt ? current->prompt->type : P_UNKNOWN;
815    if (ptype != P_MENU)
816        current = current->parent;
817    display_tree_part();
818
819    if (current == &rootmenu)
820        gtk_widget_set_sensitive(back_btn, FALSE);
821}
822
823
824void on_load_clicked(GtkButton * button, gpointer user_data)
825{
826    on_load1_activate(NULL, user_data);
827}
828
829
830void on_save_clicked(GtkButton * button, gpointer user_data)
831{
832    on_save1_activate(NULL, user_data);
833}
834
835
836void on_single_clicked(GtkButton * button, gpointer user_data)
837{
838    view_mode = SINGLE_VIEW;
839    gtk_paned_set_position(GTK_PANED(hpaned), 0);
840    gtk_widget_hide(tree1_w);
841    current = &rootmenu;
842    display_tree_part();
843}
844
845
846void on_split_clicked(GtkButton * button, gpointer user_data)
847{
848    gint w, h;
849    view_mode = SPLIT_VIEW;
850    gtk_widget_show(tree1_w);
851    gtk_window_get_default_size(GTK_WINDOW(main_wnd), &w, &h);
852    gtk_paned_set_position(GTK_PANED(hpaned), w / 2);
853    if (tree2)
854        gtk_tree_store_clear(tree2);
855    display_list();
856
857    /* Disable back btn, like in full mode. */
858    gtk_widget_set_sensitive(back_btn, FALSE);
859}
860
861
862void on_full_clicked(GtkButton * button, gpointer user_data)
863{
864    view_mode = FULL_VIEW;
865    gtk_paned_set_position(GTK_PANED(hpaned), 0);
866    gtk_widget_hide(tree1_w);
867    if (tree2)
868        gtk_tree_store_clear(tree2);
869    display_tree(&rootmenu);
870    gtk_widget_set_sensitive(back_btn, FALSE);
871}
872
873
874void on_collapse_clicked(GtkButton * button, gpointer user_data)
875{
876    gtk_tree_view_collapse_all(GTK_TREE_VIEW(tree2_w));
877}
878
879
880void on_expand_clicked(GtkButton * button, gpointer user_data)
881{
882    gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w));
883}
884
885
886/* CTree Callbacks */
887
888/* Change hex/int/string value in the cell */
889static void renderer_edited(GtkCellRendererText * cell,
890                const gchar * path_string,
891                const gchar * new_text, gpointer user_data)
892{
893    GtkTreePath *path = gtk_tree_path_new_from_string(path_string);
894    GtkTreeIter iter;
895    const char *old_def, *new_def;
896    struct menu *menu;
897    struct symbol *sym;
898
899    if (!gtk_tree_model_get_iter(model2, &iter, path))
900        return;
901
902    gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
903    sym = menu->sym;
904
905    gtk_tree_model_get(model2, &iter, COL_VALUE, &old_def, -1);
906    new_def = new_text;
907
908    sym_set_string_value(sym, new_def);
909
910    config_changed = TRUE;
911    update_tree(&rootmenu, NULL);
912
913    gtk_tree_path_free(path);
914}
915
916/* Change the value of a symbol and update the tree */
917static void change_sym_value(struct menu *menu, gint col)
918{
919    struct symbol *sym = menu->sym;
920    tristate oldval, newval;
921
922    if (!sym)
923        return;
924
925    if (col == COL_NO)
926        newval = no;
927    else if (col == COL_MOD)
928        newval = mod;
929    else if (col == COL_YES)
930        newval = yes;
931    else
932        return;
933
934    switch (sym_get_type(sym)) {
935    case S_BOOLEAN:
936    case S_TRISTATE:
937        oldval = sym_get_tristate_value(sym);
938        if (!sym_tristate_within_range(sym, newval))
939            newval = yes;
940        sym_set_tristate_value(sym, newval);
941        config_changed = TRUE;
942        if (view_mode == FULL_VIEW)
943            update_tree(&rootmenu, NULL);
944        else if (view_mode == SPLIT_VIEW) {
945            update_tree(browsed, NULL);
946            display_list();
947        }
948        else if (view_mode == SINGLE_VIEW)
949            display_tree_part();    //fixme: keep exp/coll
950        break;
951    case S_INT:
952    case S_HEX:
953    case S_STRING:
954    default:
955        break;
956    }
957}
958
959static void toggle_sym_value(struct menu *menu)
960{
961    if (!menu->sym)
962        return;
963
964    sym_toggle_tristate_value(menu->sym);
965    if (view_mode == FULL_VIEW)
966        update_tree(&rootmenu, NULL);
967    else if (view_mode == SPLIT_VIEW) {
968        update_tree(browsed, NULL);
969        display_list();
970    }
971    else if (view_mode == SINGLE_VIEW)
972        display_tree_part();    //fixme: keep exp/coll
973}
974
975static void renderer_toggled(GtkCellRendererToggle * cell,
976                 gchar * path_string, gpointer user_data)
977{
978    GtkTreePath *path, *sel_path = NULL;
979    GtkTreeIter iter, sel_iter;
980    GtkTreeSelection *sel;
981    struct menu *menu;
982
983    path = gtk_tree_path_new_from_string(path_string);
984    if (!gtk_tree_model_get_iter(model2, &iter, path))
985        return;
986
987    sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree2_w));
988    if (gtk_tree_selection_get_selected(sel, NULL, &sel_iter))
989        sel_path = gtk_tree_model_get_path(model2, &sel_iter);
990    if (!sel_path)
991        goto out1;
992    if (gtk_tree_path_compare(path, sel_path))
993        goto out2;
994
995    gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
996    toggle_sym_value(menu);
997
998      out2:
999    gtk_tree_path_free(sel_path);
1000      out1:
1001    gtk_tree_path_free(path);
1002}
1003
1004static gint column2index(GtkTreeViewColumn * column)
1005{
1006    gint i;
1007
1008    for (i = 0; i < COL_NUMBER; i++) {
1009        GtkTreeViewColumn *col;
1010
1011        col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), i);
1012        if (col == column)
1013            return i;
1014    }
1015
1016    return -1;
1017}
1018
1019
1020/* User click: update choice (full) or goes down (single) */
1021gboolean
1022on_treeview2_button_press_event(GtkWidget * widget,
1023                GdkEventButton * event, gpointer user_data)
1024{
1025    GtkTreeView *view = GTK_TREE_VIEW(widget);
1026    GtkTreePath *path;
1027    GtkTreeViewColumn *column;
1028    GtkTreeIter iter;
1029    struct menu *menu;
1030    gint col;
1031
1032#if GTK_CHECK_VERSION(2,1,4) // bug in ctree with earlier version of GTK
1033    gint tx = (gint) event->x;
1034    gint ty = (gint) event->y;
1035    gint cx, cy;
1036
1037    gtk_tree_view_get_path_at_pos(view, tx, ty, &path, &column, &cx,
1038                      &cy);
1039#else
1040    gtk_tree_view_get_cursor(view, &path, &column);
1041#endif
1042    if (path == NULL)
1043        return FALSE;
1044
1045    if (!gtk_tree_model_get_iter(model2, &iter, path))
1046        return FALSE;
1047    gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
1048
1049    col = column2index(column);
1050    if (event->type == GDK_2BUTTON_PRESS) {
1051        enum prop_type ptype;
1052        ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
1053
1054        if (ptype == P_MENU && view_mode != FULL_VIEW && col == COL_OPTION) {
1055            // goes down into menu
1056            current = menu;
1057            display_tree_part();
1058            gtk_widget_set_sensitive(back_btn, TRUE);
1059        } else if ((col == COL_OPTION)) {
1060            toggle_sym_value(menu);
1061            gtk_tree_view_expand_row(view, path, TRUE);
1062        }
1063    } else {
1064        if (col == COL_VALUE) {
1065            toggle_sym_value(menu);
1066            gtk_tree_view_expand_row(view, path, TRUE);
1067        } else if (col == COL_NO || col == COL_MOD
1068               || col == COL_YES) {
1069            change_sym_value(menu, col);
1070            gtk_tree_view_expand_row(view, path, TRUE);
1071        }
1072    }
1073
1074    return FALSE;
1075}
1076
1077/* Key pressed: update choice */
1078gboolean
1079on_treeview2_key_press_event(GtkWidget * widget,
1080                 GdkEventKey * event, gpointer user_data)
1081{
1082    GtkTreeView *view = GTK_TREE_VIEW(widget);
1083    GtkTreePath *path;
1084    GtkTreeViewColumn *column;
1085    GtkTreeIter iter;
1086    struct menu *menu;
1087    gint col;
1088
1089    gtk_tree_view_get_cursor(view, &path, &column);
1090    if (path == NULL)
1091        return FALSE;
1092
1093    if (event->keyval == GDK_space) {
1094        if (gtk_tree_view_row_expanded(view, path))
1095            gtk_tree_view_collapse_row(view, path);
1096        else
1097            gtk_tree_view_expand_row(view, path, FALSE);
1098        return TRUE;
1099    }
1100    if (event->keyval == GDK_KP_Enter) {
1101    }
1102    if (widget == tree1_w)
1103        return FALSE;
1104
1105    gtk_tree_model_get_iter(model2, &iter, path);
1106    gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
1107
1108    if (!strcasecmp(event->string, "n"))
1109        col = COL_NO;
1110    else if (!strcasecmp(event->string, "m"))
1111        col = COL_MOD;
1112    else if (!strcasecmp(event->string, "y"))
1113        col = COL_YES;
1114    else
1115        col = -1;
1116    change_sym_value(menu, col);
1117
1118    return FALSE;
1119}
1120
1121
1122/* Row selection changed: update help */
1123void
1124on_treeview2_cursor_changed(GtkTreeView * treeview, gpointer user_data)
1125{
1126    GtkTreeSelection *selection;
1127    GtkTreeIter iter;
1128    struct menu *menu;
1129
1130    selection = gtk_tree_view_get_selection(treeview);
1131    if (gtk_tree_selection_get_selected(selection, &model2, &iter)) {
1132        gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
1133        text_insert_help(menu);
1134    }
1135}
1136
1137
1138/* User click: display sub-tree in the right frame. */
1139gboolean
1140on_treeview1_button_press_event(GtkWidget * widget,
1141                GdkEventButton * event, gpointer user_data)
1142{
1143    GtkTreeView *view = GTK_TREE_VIEW(widget);
1144    GtkTreePath *path;
1145    GtkTreeViewColumn *column;
1146    GtkTreeIter iter;
1147    struct menu *menu;
1148
1149    gint tx = (gint) event->x;
1150    gint ty = (gint) event->y;
1151    gint cx, cy;
1152
1153    gtk_tree_view_get_path_at_pos(view, tx, ty, &path, &column, &cx,
1154                      &cy);
1155    if (path == NULL)
1156        return FALSE;
1157
1158    gtk_tree_model_get_iter(model1, &iter, path);
1159    gtk_tree_model_get(model1, &iter, COL_MENU, &menu, -1);
1160
1161    if (event->type == GDK_2BUTTON_PRESS) {
1162        toggle_sym_value(menu);
1163        current = menu;
1164        display_tree_part();
1165    } else {
1166        browsed = menu;
1167        display_tree_part();
1168    }
1169
1170    gtk_widget_realize(tree2_w);
1171    gtk_tree_view_set_cursor(view, path, NULL, FALSE);
1172    gtk_widget_grab_focus(tree2_w);
1173
1174    return FALSE;
1175}
1176
1177
1178/* Fill a row of strings */
1179static gchar **fill_row(struct menu *menu)
1180{
1181    static gchar *row[COL_NUMBER];
1182    struct symbol *sym = menu->sym;
1183    const char *def;
1184    int stype;
1185    tristate val;
1186    enum prop_type ptype;
1187    int i;
1188
1189    for (i = COL_OPTION; i <= COL_COLOR; i++)
1190        g_free(row[i]);
1191    memset(row, 0, sizeof(row));
1192
1193    row[COL_OPTION] =
1194        g_strdup_printf("%s %s", menu_get_prompt(menu),
1195                sym ? (sym->
1196                   flags & SYMBOL_NEW ? "(NEW)" : "") :
1197                "");
1198
1199    if (show_all && !menu_is_visible(menu))
1200        row[COL_COLOR] = g_strdup("DarkGray");
1201    else
1202        row[COL_COLOR] = g_strdup("Black");
1203
1204    ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
1205    switch (ptype) {
1206    case P_MENU:
1207        row[COL_PIXBUF] = (gchar *) xpm_menu;
1208        if (view_mode == SINGLE_VIEW)
1209            row[COL_PIXVIS] = GINT_TO_POINTER(TRUE);
1210        row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
1211        break;
1212    case P_COMMENT:
1213        row[COL_PIXBUF] = (gchar *) xpm_void;
1214        row[COL_PIXVIS] = GINT_TO_POINTER(FALSE);
1215        row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
1216        break;
1217    default:
1218        row[COL_PIXBUF] = (gchar *) xpm_void;
1219        row[COL_PIXVIS] = GINT_TO_POINTER(FALSE);
1220        row[COL_BTNVIS] = GINT_TO_POINTER(TRUE);
1221        break;
1222    }
1223
1224    if (!sym)
1225        return row;
1226    row[COL_NAME] = g_strdup(sym->name);
1227
1228    sym_calc_value(sym);
1229    sym->flags &= ~SYMBOL_CHANGED;
1230
1231    if (sym_is_choice(sym)) {   // parse childs for getting final value
1232        struct menu *child;
1233        struct symbol *def_sym = sym_get_choice_value(sym);
1234        struct menu *def_menu = NULL;
1235
1236        row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
1237
1238        for (child = menu->list; child; child = child->next) {
1239            if (menu_is_visible(child)
1240                && child->sym == def_sym)
1241                def_menu = child;
1242        }
1243
1244        if (def_menu)
1245            row[COL_VALUE] =
1246                g_strdup(menu_get_prompt(def_menu));
1247    }
1248    if (sym->flags & SYMBOL_CHOICEVAL)
1249        row[COL_BTNRAD] = GINT_TO_POINTER(TRUE);
1250
1251    stype = sym_get_type(sym);
1252    switch (stype) {
1253    case S_BOOLEAN:
1254        if (GPOINTER_TO_INT(row[COL_PIXVIS]) == FALSE)
1255            row[COL_BTNVIS] = GINT_TO_POINTER(TRUE);
1256        if (sym_is_choice(sym))
1257            break;
1258    case S_TRISTATE:
1259        val = sym_get_tristate_value(sym);
1260        switch (val) {
1261        case no:
1262            row[COL_NO] = g_strdup("N");
1263            row[COL_VALUE] = g_strdup("N");
1264            row[COL_BTNACT] = GINT_TO_POINTER(FALSE);
1265            row[COL_BTNINC] = GINT_TO_POINTER(FALSE);
1266            break;
1267        case mod:
1268            row[COL_MOD] = g_strdup("M");
1269            row[COL_VALUE] = g_strdup("M");
1270            row[COL_BTNINC] = GINT_TO_POINTER(TRUE);
1271            break;
1272        case yes:
1273            row[COL_YES] = g_strdup("Y");
1274            row[COL_VALUE] = g_strdup("Y");
1275            row[COL_BTNACT] = GINT_TO_POINTER(TRUE);
1276            row[COL_BTNINC] = GINT_TO_POINTER(FALSE);
1277            break;
1278        }
1279
1280        if (val != no && sym_tristate_within_range(sym, no))
1281            row[COL_NO] = g_strdup("_");
1282        if (val != mod && sym_tristate_within_range(sym, mod))
1283            row[COL_MOD] = g_strdup("_");
1284        if (val != yes && sym_tristate_within_range(sym, yes))
1285            row[COL_YES] = g_strdup("_");
1286        break;
1287    case S_INT:
1288    case S_HEX:
1289    case S_STRING:
1290        def = sym_get_string_value(sym);
1291        row[COL_VALUE] = g_strdup(def);
1292        row[COL_EDIT] = GINT_TO_POINTER(TRUE);
1293        row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
1294        break;
1295    }
1296
1297    return row;
1298}
1299
1300
1301/* Set the node content with a row of strings */
1302static void set_node(GtkTreeIter * node, struct menu *menu, gchar ** row)
1303{
1304    GdkColor color;
1305    gboolean success;
1306    GdkPixbuf *pix;
1307
1308    pix = gdk_pixbuf_new_from_xpm_data((const char **)
1309                       row[COL_PIXBUF]);
1310
1311    gdk_color_parse(row[COL_COLOR], &color);
1312    gdk_colormap_alloc_colors(gdk_colormap_get_system(), &color, 1,
1313                  FALSE, FALSE, &success);
1314
1315    gtk_tree_store_set(tree, node,
1316               COL_OPTION, row[COL_OPTION],
1317               COL_NAME, row[COL_NAME],
1318               COL_NO, row[COL_NO],
1319               COL_MOD, row[COL_MOD],
1320               COL_YES, row[COL_YES],
1321               COL_VALUE, row[COL_VALUE],
1322               COL_MENU, (gpointer) menu,
1323               COL_COLOR, &color,
1324               COL_EDIT, GPOINTER_TO_INT(row[COL_EDIT]),
1325               COL_PIXBUF, pix,
1326               COL_PIXVIS, GPOINTER_TO_INT(row[COL_PIXVIS]),
1327               COL_BTNVIS, GPOINTER_TO_INT(row[COL_BTNVIS]),
1328               COL_BTNACT, GPOINTER_TO_INT(row[COL_BTNACT]),
1329               COL_BTNINC, GPOINTER_TO_INT(row[COL_BTNINC]),
1330               COL_BTNRAD, GPOINTER_TO_INT(row[COL_BTNRAD]),
1331               -1);
1332
1333    g_object_unref(pix);
1334}
1335
1336
1337/* Add a node to the tree */
1338static void place_node(struct menu *menu, char **row)
1339{
1340    GtkTreeIter *parent = parents[indent - 1];
1341    GtkTreeIter *node = parents[indent];
1342
1343    gtk_tree_store_append(tree, node, parent);
1344    set_node(node, menu, row);
1345}
1346
1347
1348/* Find a node in the GTK+ tree */
1349static GtkTreeIter found;
1350
1351/*
1352 * Find a menu in the GtkTree starting at parent.
1353 */
1354GtkTreeIter *gtktree_iter_find_node(GtkTreeIter * parent,
1355                    struct menu *tofind)
1356{
1357    GtkTreeIter iter;
1358    GtkTreeIter *child = &iter;
1359    gboolean valid;
1360    GtkTreeIter *ret;
1361
1362    valid = gtk_tree_model_iter_children(model2, child, parent);
1363    while (valid) {
1364        struct menu *menu;
1365
1366        gtk_tree_model_get(model2, child, 6, &menu, -1);
1367
1368        if (menu == tofind) {
1369            memcpy(&found, child, sizeof(GtkTreeIter));
1370            return &found;
1371        }
1372
1373        ret = gtktree_iter_find_node(child, tofind);
1374        if (ret)
1375            return ret;
1376
1377        valid = gtk_tree_model_iter_next(model2, child);
1378    }
1379
1380    return NULL;
1381}
1382
1383
1384/*
1385 * Update the tree by adding/removing entries
1386 * Does not change other nodes
1387 */
1388static void update_tree(struct menu *src, GtkTreeIter * dst)
1389{
1390    struct menu *child1;
1391    GtkTreeIter iter, tmp;
1392    GtkTreeIter *child2 = &iter;
1393    gboolean valid;
1394    GtkTreeIter *sibling;
1395    struct symbol *sym;
1396    struct property *prop;
1397    struct menu *menu1, *menu2;
1398
1399    if (src == &rootmenu)
1400        indent = 1;
1401
1402    valid = gtk_tree_model_iter_children(model2, child2, dst);
1403    for (child1 = src->list; child1; child1 = child1->next) {
1404
1405        prop = child1->prompt;
1406        sym = child1->sym;
1407
1408          reparse:
1409        menu1 = child1;
1410        if (valid)
1411            gtk_tree_model_get(model2, child2, COL_MENU,
1412                       &menu2, -1);
1413        else
1414            menu2 = NULL;   // force adding of a first child
1415
1416#ifdef DEBUG
1417        printf("%*c%s | %s\n", indent, ' ',
1418               menu1 ? menu_get_prompt(menu1) : "nil",
1419               menu2 ? menu_get_prompt(menu2) : "nil");
1420#endif
1421
1422        if (!menu_is_visible(child1) && !show_all) {    // remove node
1423            if (gtktree_iter_find_node(dst, menu1) != NULL) {
1424                memcpy(&tmp, child2, sizeof(GtkTreeIter));
1425                valid = gtk_tree_model_iter_next(model2,
1426                                 child2);
1427                gtk_tree_store_remove(tree2, &tmp);
1428                if (!valid)
1429                    return; // next parent
1430                else
1431                    goto reparse;   // next child
1432            } else
1433                continue;
1434        }
1435
1436        if (menu1 != menu2) {
1437            if (gtktree_iter_find_node(dst, menu1) == NULL) {   // add node
1438                if (!valid && !menu2)
1439                    sibling = NULL;
1440                else
1441                    sibling = child2;
1442                gtk_tree_store_insert_before(tree2,
1443                                 child2,
1444                                 dst, sibling);
1445                set_node(child2, menu1, fill_row(menu1));
1446                if (menu2 == NULL)
1447                    valid = TRUE;
1448            } else {    // remove node
1449                memcpy(&tmp, child2, sizeof(GtkTreeIter));
1450                valid = gtk_tree_model_iter_next(model2,
1451                                 child2);
1452                gtk_tree_store_remove(tree2, &tmp);
1453                if (!valid)
1454                    return; // next parent
1455                else
1456                    goto reparse;   // next child
1457            }
1458        } else if (sym && (sym->flags & SYMBOL_CHANGED)) {
1459            set_node(child2, menu1, fill_row(menu1));
1460        }
1461
1462        indent++;
1463        update_tree(child1, child2);
1464        indent--;
1465
1466        valid = gtk_tree_model_iter_next(model2, child2);
1467    }
1468}
1469
1470
1471/* Display the whole tree (single/split/full view) */
1472static void display_tree(struct menu *menu)
1473{
1474    struct symbol *sym;
1475    struct property *prop;
1476    struct menu *child;
1477    enum prop_type ptype;
1478
1479    if (menu == &rootmenu) {
1480        indent = 1;
1481        current = &rootmenu;
1482    }
1483
1484    for (child = menu->list; child; child = child->next) {
1485        prop = child->prompt;
1486        sym = child->sym;
1487        ptype = prop ? prop->type : P_UNKNOWN;
1488
1489        if (sym)
1490            sym->flags &= ~SYMBOL_CHANGED;
1491
1492        if ((view_mode == SPLIT_VIEW)
1493            && !(child->flags & MENU_ROOT) && (tree == tree1))
1494            continue;
1495
1496        if ((view_mode == SPLIT_VIEW) && (child->flags & MENU_ROOT)
1497            && (tree == tree2))
1498            continue;
1499
1500        if (menu_is_visible(child) || show_all)
1501            place_node(child, fill_row(child));
1502#ifdef DEBUG
1503        printf("%*c%s: ", indent, ' ', menu_get_prompt(child));
1504        printf("%s", child->flags & MENU_ROOT ? "rootmenu | " : "");
1505        dbg_print_ptype(ptype);
1506        printf(" | ");
1507        if (sym) {
1508            dbg_print_stype(sym->type);
1509            printf(" | ");
1510            dbg_print_flags(sym->flags);
1511            printf("\n");
1512        } else
1513            printf("\n");
1514#endif
1515        if ((view_mode != FULL_VIEW) && (ptype == P_MENU)
1516            && (tree == tree2))
1517            continue;
1518/*
1519        if (((menu != &rootmenu) && !(menu->flags & MENU_ROOT))
1520            || (view_mode == FULL_VIEW)
1521            || (view_mode == SPLIT_VIEW))*/
1522        if (((view_mode == SINGLE_VIEW) && (menu->flags & MENU_ROOT))
1523            || (view_mode == FULL_VIEW)
1524            || (view_mode == SPLIT_VIEW)) {
1525            indent++;
1526            display_tree(child);
1527            indent--;
1528        }
1529    }
1530}
1531
1532/* Display a part of the tree starting at current node (single/split view) */
1533static void display_tree_part(void)
1534{
1535    if (tree2)
1536        gtk_tree_store_clear(tree2);
1537    if (view_mode == SINGLE_VIEW)
1538        display_tree(current);
1539    else if (view_mode == SPLIT_VIEW)
1540        display_tree(browsed);
1541    gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w));
1542}
1543
1544/* Display the list in the left frame (split view) */
1545static void display_list(void)
1546{
1547    if (tree1)
1548        gtk_tree_store_clear(tree1);
1549
1550    tree = tree1;
1551    display_tree(&rootmenu);
1552    gtk_tree_view_expand_all(GTK_TREE_VIEW(tree1_w));
1553    tree = tree2;
1554}
1555
1556void fixup_rootmenu(struct menu *menu)
1557{
1558    struct menu *child;
1559    static int menu_cnt = 0;
1560
1561    menu->flags |= MENU_ROOT;
1562    for (child = menu->list; child; child = child->next) {
1563        if (child->prompt && child->prompt->type == P_MENU) {
1564            menu_cnt++;
1565            fixup_rootmenu(child);
1566            menu_cnt--;
1567        } else if (!menu_cnt)
1568            fixup_rootmenu(child);
1569    }
1570}
1571
1572
1573/* Main */
1574int main(int ac, char *av[])
1575{
1576    const char *name;
1577    char *env;
1578    gchar *glade_file;
1579
1580#ifndef LKC_DIRECT_LINK
1581    kconfig_load();
1582#endif
1583
1584    bindtextdomain(PACKAGE, LOCALEDIR);
1585    bind_textdomain_codeset(PACKAGE, "UTF-8");
1586    textdomain(PACKAGE);
1587
1588    /* GTK stuffs */
1589    gtk_set_locale();
1590    gtk_init(&ac, &av);
1591    glade_init();
1592
1593    //add_pixmap_directory (PACKAGE_DATA_DIR "/" PACKAGE "/pixmaps");
1594    //add_pixmap_directory (PACKAGE_SOURCE_DIR "/pixmaps");
1595
1596    /* Determine GUI path */
1597    env = getenv(SRCTREE);
1598    if (env)
1599        glade_file = g_strconcat(env, "/scripts/kconfig/gconf.glade", NULL);
1600    else if (av[0][0] == '/')
1601        glade_file = g_strconcat(av[0], ".glade", NULL);
1602    else
1603        glade_file = g_strconcat(g_get_current_dir(), "/", av[0], ".glade", NULL);
1604
1605    /* Load the interface and connect signals */
1606    init_main_window(glade_file);
1607    init_tree_model();
1608    init_left_tree();
1609    init_right_tree();
1610
1611    /* Conf stuffs */
1612    if (ac > 1 && av[1][0] == '-') {
1613        switch (av[1][1]) {
1614        case 'a':
1615            //showAll = 1;
1616            break;
1617        case 'h':
1618        case '?':
1619            printf("%s <config>\n", av[0]);
1620            exit(0);
1621        }
1622        name = av[2];
1623    } else
1624        name = av[1];
1625
1626    conf_parse(name);
1627    fixup_rootmenu(&rootmenu);
1628    conf_read(NULL);
1629
1630    switch (view_mode) {
1631    case SINGLE_VIEW:
1632        display_tree_part();
1633        break;
1634    case SPLIT_VIEW:
1635        display_list();
1636        break;
1637    case FULL_VIEW:
1638        display_tree(&rootmenu);
1639        break;
1640    }
1641
1642    gtk_main();
1643
1644    return 0;
1645}
Note: See TracBrowser for help on using the repository browser.