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