xref: /linux/scripts/kconfig/gconf.c (revision 0074281bb6316108e0cff094bd4db78ab3eee236)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2002-2003 Romain Lievin <roms@tilp.info>
4  */
5 
6 #include <stdlib.h>
7 #include "lkc.h"
8 #include "images.h"
9 
10 #include <gtk/gtk.h>
11 
12 #include <stdio.h>
13 #include <string.h>
14 #include <strings.h>
15 #include <unistd.h>
16 #include <time.h>
17 
18 enum view_mode {
19 	SINGLE_VIEW, SPLIT_VIEW, FULL_VIEW
20 };
21 
22 enum {
23 	OPT_NORMAL, OPT_ALL, OPT_PROMPT
24 };
25 
26 static gint view_mode = FULL_VIEW;
27 static gboolean show_name = TRUE;
28 static gboolean show_range = TRUE;
29 static gboolean show_value = TRUE;
30 static int opt_mode = OPT_NORMAL;
31 
32 static GtkWidget *main_wnd;
33 static GtkWidget *tree1_w;	// left  frame
34 static GtkWidget *tree2_w;	// right frame
35 static GtkWidget *text_w;
36 static GtkWidget *hpaned;
37 static GtkWidget *vpaned;
38 static GtkWidget *back_btn, *save_btn, *single_btn, *split_btn, *full_btn;
39 static GtkWidget *save_menu_item;
40 
41 static GtkTextTag *tag1, *tag2;
42 
43 static GtkTreeStore *tree1, *tree2;
44 static GdkPixbuf *pix_menu;
45 
46 static struct menu *browsed; // browsed menu for SINGLE/SPLIT view
47 static struct menu *selected; // selected entry
48 
49 enum {
50 	COL_OPTION, COL_NAME, COL_NO, COL_MOD, COL_YES, COL_VALUE,
51 	COL_MENU, COL_COLOR, COL_EDIT, COL_PIXBUF,
52 	COL_PIXVIS, COL_BTNVIS, COL_BTNACT, COL_BTNINC, COL_BTNRAD,
53 	COL_NUMBER
54 };
55 
56 static void display_tree(GtkTreeStore *store, struct menu *menu);
57 static void recreate_tree(void);
58 
conf_changed(bool dirty)59 static void conf_changed(bool dirty)
60 {
61 	gtk_widget_set_sensitive(save_btn, dirty);
62 	gtk_widget_set_sensitive(save_menu_item, dirty);
63 }
64 
65 /* Utility Functions */
66 
text_insert_msg(const char * title,const char * msg)67 static void text_insert_msg(const char *title, const char *msg)
68 {
69 	GtkTextBuffer *buffer;
70 	GtkTextIter start, end;
71 
72 	buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w));
73 	gtk_text_buffer_get_bounds(buffer, &start, &end);
74 	gtk_text_buffer_delete(buffer, &start, &end);
75 	gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_w), 15);
76 
77 	gtk_text_buffer_get_end_iter(buffer, &end);
78 	gtk_text_buffer_insert_with_tags(buffer, &end, title, -1, tag1,
79 					 NULL);
80 	gtk_text_buffer_insert_at_cursor(buffer, "\n\n", 2);
81 	gtk_text_buffer_get_end_iter(buffer, &end);
82 	gtk_text_buffer_insert_with_tags(buffer, &end, msg, -1, tag2,
83 					 NULL);
84 }
85 
text_insert_help(struct menu * menu)86 static void text_insert_help(struct menu *menu)
87 {
88 	struct gstr help = str_new();
89 
90 	menu_get_ext_help(menu, &help);
91 	text_insert_msg(menu_get_prompt(menu), str_get(&help));
92 	str_free(&help);
93 }
94 
_select_menu(GtkTreeView * view,GtkTreeModel * model,GtkTreeIter * parent,struct menu * match)95 static void _select_menu(GtkTreeView *view, GtkTreeModel *model,
96 			 GtkTreeIter *parent, struct menu *match)
97 {
98 	GtkTreeIter iter;
99 	gboolean valid;
100 
101 	valid = gtk_tree_model_iter_children(model, &iter, parent);
102 	while (valid) {
103 		struct menu *menu;
104 
105 		gtk_tree_model_get(model, &iter, COL_MENU, &menu, -1);
106 
107 		if (menu == match) {
108 			GtkTreeSelection *selection;
109 			GtkTreePath *path;
110 
111 			/*
112 			 * Expand parents to reflect the selection, and
113 			 * scroll down to it.
114 			 */
115 			path = gtk_tree_model_get_path(model, &iter);
116 			gtk_tree_view_expand_to_path(view, path);
117 			gtk_tree_view_scroll_to_cell(view, path, NULL, TRUE,
118 						     0.5, 0.0);
119 			gtk_tree_path_free(path);
120 
121 			selection = gtk_tree_view_get_selection(view);
122 			gtk_tree_selection_select_iter(selection, &iter);
123 
124 			text_insert_help(menu);
125 		}
126 
127 		_select_menu(view, model, &iter, match);
128 
129 		valid = gtk_tree_model_iter_next(model, &iter);
130 	}
131 }
132 
select_menu(GtkTreeView * view,struct menu * match)133 static void select_menu(GtkTreeView *view, struct menu *match)
134 {
135 	_select_menu(view, gtk_tree_view_get_model(view), NULL, match);
136 }
137 
_update_row_visibility(GtkTreeView * view)138 static void _update_row_visibility(GtkTreeView *view)
139 {
140 	GtkTreeModelFilter *filter = GTK_TREE_MODEL_FILTER(gtk_tree_view_get_model(view));
141 
142 	gtk_tree_model_filter_refilter(filter);
143 }
144 
update_row_visibility(void)145 static void update_row_visibility(void)
146 {
147 	if (view_mode == SPLIT_VIEW)
148 		_update_row_visibility(GTK_TREE_VIEW(tree1_w));
149 	_update_row_visibility(GTK_TREE_VIEW(tree2_w));
150 }
151 
set_node(GtkTreeStore * tree,GtkTreeIter * node,struct menu * menu)152 static void set_node(GtkTreeStore *tree, GtkTreeIter *node, struct menu *menu)
153 {
154 	struct symbol *sym = menu->sym;
155 	tristate val;
156 	gchar *option;
157 	const gchar *_no = "";
158 	const gchar *_mod = "";
159 	const gchar *_yes = "";
160 	const gchar *value = "";
161 	GdkRGBA color;
162 	gboolean editable = FALSE;
163 	gboolean btnvis = FALSE;
164 
165 	option = g_strdup_printf("%s %s %s %s",
166 				 menu->type == M_COMMENT ? "***" : "",
167 				 menu_get_prompt(menu),
168 				 menu->type == M_COMMENT ? "***" : "",
169 				 sym && !sym_has_value(sym) ? "(NEW)" : "");
170 
171 	gdk_rgba_parse(&color, menu_is_visible(menu) ? "Black" : "DarkGray");
172 
173 	if (!sym)
174 		goto set;
175 
176 	sym_calc_value(sym);
177 
178 	if (menu->type == M_CHOICE) {	// parse children to get a final value
179 		struct symbol *def_sym = sym_calc_choice(menu);
180 		struct menu *def_menu = NULL;
181 
182 		for (struct menu *child = menu->list; child; child = child->next) {
183 			if (menu_is_visible(child) && child->sym == def_sym)
184 				def_menu = child;
185 		}
186 
187 		if (def_menu)
188 			value = menu_get_prompt(def_menu);
189 
190 		goto set;
191 	}
192 
193 	switch (sym_get_type(sym)) {
194 	case S_BOOLEAN:
195 	case S_TRISTATE:
196 
197 		btnvis = TRUE;
198 
199 		val = sym_get_tristate_value(sym);
200 		switch (val) {
201 		case no:
202 			_no = "N";
203 			value = "N";
204 			break;
205 		case mod:
206 			_mod = "M";
207 			value = "M";
208 			break;
209 		case yes:
210 			_yes = "Y";
211 			value = "Y";
212 			break;
213 		}
214 
215 		if (val != no && sym_tristate_within_range(sym, no))
216 			_no = "_";
217 		if (val != mod && sym_tristate_within_range(sym, mod))
218 			_mod = "_";
219 		if (val != yes && sym_tristate_within_range(sym, yes))
220 			_yes = "_";
221 		break;
222 	default:
223 		value = sym_get_string_value(sym);
224 		editable = TRUE;
225 		break;
226 	}
227 
228 set:
229 	gtk_tree_store_set(tree, node,
230 			   COL_OPTION, option,
231 			   COL_NAME, sym ? sym->name : "",
232 			   COL_NO, _no,
233 			   COL_MOD, _mod,
234 			   COL_YES, _yes,
235 			   COL_VALUE, value,
236 			   COL_MENU, (gpointer) menu,
237 			   COL_COLOR, &color,
238 			   COL_EDIT, editable,
239 			   COL_PIXBUF, pix_menu,
240 			   COL_PIXVIS, view_mode == SINGLE_VIEW && menu->type == M_MENU,
241 			   COL_BTNVIS, btnvis,
242 			   COL_BTNACT, _yes[0] == 'Y',
243 			   COL_BTNINC, _mod[0] == 'M',
244 			   COL_BTNRAD, sym && sym_is_choice_value(sym),
245 			   -1);
246 
247 	g_free(option);
248 }
249 
_update_tree(GtkTreeStore * store,GtkTreeIter * parent)250 static void _update_tree(GtkTreeStore *store, GtkTreeIter *parent)
251 {
252 	GtkTreeModel *model = GTK_TREE_MODEL(store);
253 	GtkTreeIter iter;
254 	gboolean valid;
255 
256 	valid = gtk_tree_model_iter_children(model, &iter, parent);
257 	while (valid) {
258 		struct menu *menu;
259 
260 		gtk_tree_model_get(model, &iter, COL_MENU, &menu, -1);
261 
262 		if (menu)
263 			set_node(store, &iter, menu);
264 
265 		_update_tree(store, &iter);
266 
267 		valid = gtk_tree_model_iter_next(model, &iter);
268 	}
269 }
270 
update_tree(GtkTreeStore * store)271 static void update_tree(GtkTreeStore *store)
272 {
273 	_update_tree(store, NULL);
274 	update_row_visibility();
275 }
276 
update_trees(void)277 static void update_trees(void)
278 {
279 	if (view_mode == SPLIT_VIEW)
280 		update_tree(tree1);
281 	update_tree(tree2);
282 }
283 
set_view_mode(enum view_mode mode)284 static void set_view_mode(enum view_mode mode)
285 {
286 	view_mode = mode;
287 
288 	if (mode == SPLIT_VIEW) { // two panes
289 		gint w;
290 
291 		gtk_widget_show(tree1_w);
292 		gtk_window_get_default_size(GTK_WINDOW(main_wnd), &w, NULL);
293 		gtk_paned_set_position(GTK_PANED(hpaned), w / 2);
294 	} else {
295 		gtk_widget_hide(tree1_w);
296 		gtk_paned_set_position(GTK_PANED(hpaned), 0);
297 	}
298 
299 	gtk_widget_set_sensitive(single_btn, TRUE);
300 	gtk_widget_set_sensitive(split_btn, TRUE);
301 	gtk_widget_set_sensitive(full_btn, TRUE);
302 
303 	switch (mode) {
304 	case SINGLE_VIEW:
305 		if (selected)
306 			browsed = menu_get_parent_menu(selected) ?: &rootmenu;
307 		else
308 			browsed = &rootmenu;
309 		recreate_tree();
310 		text_insert_msg("", "");
311 		select_menu(GTK_TREE_VIEW(tree2_w), selected);
312 		gtk_widget_set_sensitive(single_btn, FALSE);
313 		break;
314 	case SPLIT_VIEW:
315 		browsed = selected;
316 		while (browsed && !(browsed->flags & MENU_ROOT))
317 			browsed = browsed->parent;
318 		gtk_tree_store_clear(tree1);
319 		display_tree(tree1, &rootmenu);
320 		gtk_tree_view_expand_all(GTK_TREE_VIEW(tree1_w));
321 		gtk_tree_store_clear(tree2);
322 		if (browsed)
323 			display_tree(tree2, browsed);
324 		text_insert_msg("", "");
325 		select_menu(GTK_TREE_VIEW(tree1_w), browsed);
326 		select_menu(GTK_TREE_VIEW(tree2_w), selected);
327 		gtk_widget_set_sensitive(split_btn, FALSE);
328 		break;
329 	case FULL_VIEW:
330 		gtk_tree_store_clear(tree2);
331 		display_tree(tree2, &rootmenu);
332 		text_insert_msg("", "");
333 		select_menu(GTK_TREE_VIEW(tree2_w), selected);
334 		gtk_widget_set_sensitive(full_btn, FALSE);
335 		break;
336 	}
337 
338 	gtk_widget_set_sensitive(back_btn,
339 				 mode == SINGLE_VIEW && browsed != &rootmenu);
340 }
341 
342 /* Menu & Toolbar Callbacks */
343 
on_load1_activate(GtkMenuItem * menuitem,gpointer user_data)344 static void on_load1_activate(GtkMenuItem *menuitem, gpointer user_data)
345 {
346 	GtkWidget *dialog;
347 	GtkFileChooser *chooser;
348 	gint res;
349 
350 	dialog = gtk_file_chooser_dialog_new("Load file...",
351 					     GTK_WINDOW(user_data),
352 					     GTK_FILE_CHOOSER_ACTION_OPEN,
353 					     "_Cancel", GTK_RESPONSE_CANCEL,
354 					     "_Open", GTK_RESPONSE_ACCEPT,
355 					     NULL);
356 
357 	chooser = GTK_FILE_CHOOSER(dialog);
358 	gtk_file_chooser_set_filename(chooser, conf_get_configname());
359 
360 	res = gtk_dialog_run(GTK_DIALOG(dialog));
361 	if (res == GTK_RESPONSE_ACCEPT) {
362 		char *filename;
363 
364 		filename = gtk_file_chooser_get_filename(chooser);
365 
366 		if (conf_read(filename))
367 			text_insert_msg("Error",
368 					"Unable to load configuration!");
369 		else
370 			update_trees();
371 
372 		g_free(filename);
373 	}
374 
375 	gtk_widget_destroy(GTK_WIDGET(dialog));
376 }
377 
on_save_activate(GtkMenuItem * menuitem,gpointer user_data)378 static void on_save_activate(GtkMenuItem *menuitem, gpointer user_data)
379 {
380 	if (conf_write(NULL))
381 		text_insert_msg("Error", "Unable to save configuration !");
382 	conf_write_autoconf(0);
383 }
384 
on_save_as1_activate(GtkMenuItem * menuitem,gpointer user_data)385 static void on_save_as1_activate(GtkMenuItem *menuitem, gpointer user_data)
386 {
387 	GtkWidget *dialog;
388 	GtkFileChooser *chooser;
389 	gint res;
390 
391 	dialog = gtk_file_chooser_dialog_new("Save file as...",
392 					     GTK_WINDOW(user_data),
393 					     GTK_FILE_CHOOSER_ACTION_SAVE,
394 					     "_Cancel", GTK_RESPONSE_CANCEL,
395 					     "_Save", GTK_RESPONSE_ACCEPT,
396 					     NULL);
397 
398 	chooser = GTK_FILE_CHOOSER(dialog);
399 	gtk_file_chooser_set_filename(chooser, conf_get_configname());
400 
401 	res = gtk_dialog_run(GTK_DIALOG(dialog));
402 	if (res == GTK_RESPONSE_ACCEPT) {
403 		char *filename;
404 
405 		filename = gtk_file_chooser_get_filename(chooser);
406 
407 		if (conf_write(filename))
408 			text_insert_msg("Error",
409 					"Unable to save configuration !");
410 
411 		g_free(filename);
412 	}
413 
414 	gtk_widget_destroy(dialog);
415 }
416 
on_show_name1_activate(GtkMenuItem * menuitem,gpointer user_data)417 static void on_show_name1_activate(GtkMenuItem *menuitem, gpointer user_data)
418 {
419 	GtkTreeViewColumn *col;
420 
421 	show_name = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menuitem));
422 	col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_NAME);
423 	if (col)
424 		gtk_tree_view_column_set_visible(col, show_name);
425 }
426 
on_show_range1_activate(GtkMenuItem * menuitem,gpointer user_data)427 static void on_show_range1_activate(GtkMenuItem *menuitem, gpointer user_data)
428 {
429 	GtkTreeViewColumn *col;
430 
431 	show_range = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menuitem));
432 	col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_NO);
433 	if (col)
434 		gtk_tree_view_column_set_visible(col, show_range);
435 	col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_MOD);
436 	if (col)
437 		gtk_tree_view_column_set_visible(col, show_range);
438 	col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_YES);
439 	if (col)
440 		gtk_tree_view_column_set_visible(col, show_range);
441 
442 }
443 
on_show_data1_activate(GtkMenuItem * menuitem,gpointer user_data)444 static void on_show_data1_activate(GtkMenuItem *menuitem, gpointer user_data)
445 {
446 	GtkTreeViewColumn *col;
447 
448 	show_value = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menuitem));
449 	col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_VALUE);
450 	if (col)
451 		gtk_tree_view_column_set_visible(col, show_value);
452 }
453 
on_set_option_mode1_activate(GtkMenuItem * menuitem,gpointer user_data)454 static void on_set_option_mode1_activate(GtkMenuItem *menuitem,
455 					 gpointer user_data)
456 {
457 	opt_mode = OPT_NORMAL;
458 	update_row_visibility();
459 }
460 
on_set_option_mode2_activate(GtkMenuItem * menuitem,gpointer user_data)461 static void on_set_option_mode2_activate(GtkMenuItem *menuitem,
462 					 gpointer user_data)
463 {
464 	opt_mode = OPT_ALL;
465 	update_row_visibility();
466 }
467 
on_set_option_mode3_activate(GtkMenuItem * menuitem,gpointer user_data)468 static void on_set_option_mode3_activate(GtkMenuItem *menuitem,
469 					 gpointer user_data)
470 {
471 	opt_mode = OPT_PROMPT;
472 	update_row_visibility();
473 }
474 
on_introduction1_activate(GtkMenuItem * menuitem,gpointer user_data)475 static void on_introduction1_activate(GtkMenuItem *menuitem, gpointer user_data)
476 {
477 	GtkWidget *dialog;
478 	const gchar *intro_text =
479 	    "Welcome to gconfig, the GTK+ graphical configuration tool.\n"
480 	    "For each option, a blank box indicates the feature is disabled, a\n"
481 	    "check indicates it is enabled, and a dot indicates that it is to\n"
482 	    "be compiled as a module.  Clicking on the box will cycle through the three states.\n"
483 	    "\n"
484 	    "If you do not see an option (e.g., a device driver) that you\n"
485 	    "believe should be present, try turning on Show All Options\n"
486 	    "under the Options menu.\n"
487 	    "Although there is no cross reference yet to help you figure out\n"
488 	    "what other options must be enabled to support the option you\n"
489 	    "are interested in, you can still view the help of a grayed-out\n"
490 	    "option.";
491 
492 	dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
493 					GTK_DIALOG_DESTROY_WITH_PARENT,
494 					GTK_MESSAGE_INFO,
495 					GTK_BUTTONS_CLOSE, "%s", intro_text);
496 	gtk_dialog_run(GTK_DIALOG(dialog));
497 	gtk_widget_destroy(dialog);
498 }
499 
on_about1_activate(GtkMenuItem * menuitem,gpointer user_data)500 static void on_about1_activate(GtkMenuItem *menuitem, gpointer user_data)
501 {
502 	GtkWidget *dialog;
503 	const gchar *about_text =
504 	    "gconfig is copyright (c) 2002 Romain Lievin <roms@lpg.ticalc.org>.\n"
505 	      "Based on the source code from Roman Zippel.\n";
506 
507 	dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
508 					GTK_DIALOG_DESTROY_WITH_PARENT,
509 					GTK_MESSAGE_INFO,
510 					GTK_BUTTONS_CLOSE, "%s\nGTK version: %d.%d.%d",
511 					about_text,
512 					gtk_get_major_version(),
513 					gtk_get_minor_version(),
514 					gtk_get_micro_version());
515 	gtk_dialog_run(GTK_DIALOG(dialog));
516 	gtk_widget_destroy(dialog);
517 }
518 
on_license1_activate(GtkMenuItem * menuitem,gpointer user_data)519 static void on_license1_activate(GtkMenuItem *menuitem, gpointer user_data)
520 {
521 	GtkWidget *dialog;
522 	const gchar *license_text =
523 	    "gconfig is released under the terms of the GNU GPL v2.\n"
524 	      "For more information, please see the source code or\n"
525 	      "visit http://www.fsf.org/licenses/licenses.html\n";
526 
527 	dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
528 					GTK_DIALOG_DESTROY_WITH_PARENT,
529 					GTK_MESSAGE_INFO,
530 					GTK_BUTTONS_CLOSE, "%s", license_text);
531 	gtk_dialog_run(GTK_DIALOG(dialog));
532 	gtk_widget_destroy(dialog);
533 }
534 
535 /* toolbar handlers */
on_back_clicked(GtkButton * button,gpointer user_data)536 static void on_back_clicked(GtkButton *button, gpointer user_data)
537 {
538 	browsed = menu_get_parent_menu(browsed) ?: &rootmenu;
539 
540 	recreate_tree();
541 
542 	if (browsed == &rootmenu)
543 		gtk_widget_set_sensitive(back_btn, FALSE);
544 }
545 
on_load_clicked(GtkButton * button,gpointer user_data)546 static void on_load_clicked(GtkButton *button, gpointer user_data)
547 {
548 	on_load1_activate(NULL, user_data);
549 }
550 
on_save_clicked(GtkButton * button,gpointer user_data)551 static void on_save_clicked(GtkButton *button, gpointer user_data)
552 {
553 	on_save_activate(NULL, user_data);
554 }
555 
on_single_clicked(GtkButton * button,gpointer user_data)556 static void on_single_clicked(GtkButton *button, gpointer user_data)
557 {
558 	set_view_mode(SINGLE_VIEW);
559 }
560 
on_split_clicked(GtkButton * button,gpointer user_data)561 static void on_split_clicked(GtkButton *button, gpointer user_data)
562 {
563 	set_view_mode(SPLIT_VIEW);
564 }
565 
on_full_clicked(GtkButton * button,gpointer user_data)566 static void on_full_clicked(GtkButton *button, gpointer user_data)
567 {
568 	set_view_mode(FULL_VIEW);
569 }
570 
on_collapse_clicked(GtkButton * button,gpointer user_data)571 static void on_collapse_clicked(GtkButton *button, gpointer user_data)
572 {
573 	gtk_tree_view_collapse_all(GTK_TREE_VIEW(tree2_w));
574 }
575 
on_expand_clicked(GtkButton * button,gpointer user_data)576 static void on_expand_clicked(GtkButton *button, gpointer user_data)
577 {
578 	gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w));
579 }
580 
581 /* Main Windows Callbacks */
582 
on_window1_destroy(GtkWidget * widget,gpointer user_data)583 static void on_window1_destroy(GtkWidget *widget, gpointer user_data)
584 {
585 	gtk_main_quit();
586 }
587 
on_window1_configure(GtkWidget * self,GdkEventConfigure * event,gpointer user_data)588 static gboolean on_window1_configure(GtkWidget *self,
589 				     GdkEventConfigure *event,
590 				     gpointer user_data)
591 {
592 	gtk_paned_set_position(GTK_PANED(vpaned), 2 * event->height / 3);
593 	return FALSE;
594 }
595 
on_window1_delete_event(GtkWidget * widget,GdkEvent * event,gpointer user_data)596 static gboolean on_window1_delete_event(GtkWidget *widget, GdkEvent *event,
597 					gpointer user_data)
598 {
599 	GtkWidget *dialog, *label, *content_area;
600 	gint result;
601 	gint ret = FALSE;
602 
603 	if (!conf_get_changed())
604 		return FALSE;
605 
606 	dialog = gtk_dialog_new_with_buttons("Warning !",
607 					     GTK_WINDOW(main_wnd),
608 					     (GtkDialogFlags)
609 					     (GTK_DIALOG_MODAL |
610 					      GTK_DIALOG_DESTROY_WITH_PARENT),
611 					     "_OK",
612 					     GTK_RESPONSE_YES,
613 					     "_No",
614 					     GTK_RESPONSE_NO,
615 					     "_Cancel",
616 					     GTK_RESPONSE_CANCEL, NULL);
617 	gtk_dialog_set_default_response(GTK_DIALOG(dialog),
618 					GTK_RESPONSE_CANCEL);
619 
620 	label = gtk_label_new("\nSave configuration ?\n");
621 	content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
622 	gtk_container_add(GTK_CONTAINER(content_area), label);
623 	gtk_widget_show(label);
624 
625 	result = gtk_dialog_run(GTK_DIALOG(dialog));
626 	switch (result) {
627 	case GTK_RESPONSE_YES:
628 		on_save_activate(NULL, NULL);
629 		break;
630 	case GTK_RESPONSE_NO:
631 		break;
632 	case GTK_RESPONSE_CANCEL:
633 	case GTK_RESPONSE_DELETE_EVENT:
634 	default:
635 		ret = TRUE;
636 		break;
637 	}
638 
639 	gtk_widget_destroy(dialog);
640 
641 	if (!ret)
642 		g_object_unref(pix_menu);
643 
644 	return ret;
645 }
646 
on_quit1_activate(GtkMenuItem * menuitem,gpointer user_data)647 static void on_quit1_activate(GtkMenuItem *menuitem, gpointer user_data)
648 {
649 	if (!on_window1_delete_event(NULL, NULL, NULL))
650 		gtk_widget_destroy(GTK_WIDGET(main_wnd));
651 }
652 
653 /* CTree Callbacks */
654 
655 /* Change hex/int/string value in the cell */
renderer_edited(GtkCellRendererText * cell,const gchar * path_string,const gchar * new_text,gpointer user_data)656 static void renderer_edited(GtkCellRendererText * cell,
657 			    const gchar * path_string,
658 			    const gchar * new_text, gpointer user_data)
659 {
660 	GtkTreeView *view = GTK_TREE_VIEW(user_data);
661 	GtkTreeModel *model = gtk_tree_view_get_model(view);
662 	GtkTreePath *path = gtk_tree_path_new_from_string(path_string);
663 	GtkTreeIter iter;
664 	const char *old_def, *new_def;
665 	struct menu *menu;
666 	struct symbol *sym;
667 
668 	if (!gtk_tree_model_get_iter(model, &iter, path))
669 		goto free;
670 
671 	gtk_tree_model_get(model, &iter, COL_MENU, &menu, -1);
672 	sym = menu->sym;
673 
674 	gtk_tree_model_get(model, &iter, COL_VALUE, &old_def, -1);
675 	new_def = new_text;
676 
677 	sym_set_string_value(sym, new_def);
678 
679 	update_trees();
680 
681 free:
682 	gtk_tree_path_free(path);
683 }
684 
685 /* Change the value of a symbol and update the tree */
change_sym_value(struct menu * menu,gint col)686 static void change_sym_value(struct menu *menu, gint col)
687 {
688 	struct symbol *sym = menu->sym;
689 	tristate newval;
690 
691 	if (!sym)
692 		return;
693 
694 	if (col == COL_NO)
695 		newval = no;
696 	else if (col == COL_MOD)
697 		newval = mod;
698 	else if (col == COL_YES)
699 		newval = yes;
700 	else
701 		return;
702 
703 	switch (sym_get_type(sym)) {
704 	case S_BOOLEAN:
705 	case S_TRISTATE:
706 		if (!sym_tristate_within_range(sym, newval))
707 			newval = yes;
708 		sym_set_tristate_value(sym, newval);
709 		update_trees();
710 		break;
711 	case S_INT:
712 	case S_HEX:
713 	case S_STRING:
714 	default:
715 		break;
716 	}
717 }
718 
toggle_sym_value(struct menu * menu)719 static void toggle_sym_value(struct menu *menu)
720 {
721 	if (!menu->sym)
722 		return;
723 
724 	sym_toggle_tristate_value(menu->sym);
725 	update_trees();
726 }
727 
column2index(GtkTreeViewColumn * column)728 static gint column2index(GtkTreeViewColumn * column)
729 {
730 	gint i;
731 
732 	for (i = 0; i < COL_NUMBER; i++) {
733 		GtkTreeViewColumn *col;
734 
735 		col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), i);
736 		if (col == column)
737 			return i;
738 	}
739 
740 	return -1;
741 }
742 
743 
744 /* User click: update choice (full) or goes down (single) */
on_treeview2_button_press_event(GtkWidget * widget,GdkEventButton * event,gpointer user_data)745 static gboolean on_treeview2_button_press_event(GtkWidget *widget,
746 						GdkEventButton *event,
747 						gpointer user_data)
748 {
749 	GtkTreeView *view = GTK_TREE_VIEW(widget);
750 	GtkTreeModel *model = gtk_tree_view_get_model(view);
751 	GtkTreePath *path;
752 	GtkTreeViewColumn *column;
753 	GtkTreeIter iter;
754 	struct menu *menu;
755 	gint col;
756 	gint tx = (gint) event->x;
757 	gint ty = (gint) event->y;
758 
759 	gtk_tree_view_get_path_at_pos(view, tx, ty, &path, &column, NULL, NULL);
760 	if (path == NULL)
761 		return FALSE;
762 
763 	if (!gtk_tree_model_get_iter(model, &iter, path))
764 		return FALSE;
765 	gtk_tree_model_get(model, &iter, COL_MENU, &menu, -1);
766 
767 	selected = menu;
768 
769 	col = column2index(column);
770 	if (event->type == GDK_2BUTTON_PRESS) {
771 		enum prop_type ptype;
772 		ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
773 
774 		if (ptype == P_MENU && view_mode == SINGLE_VIEW && col == COL_OPTION) {
775 			// goes down into menu
776 			browsed = menu;
777 			recreate_tree();
778 			gtk_widget_set_sensitive(back_btn, TRUE);
779 		} else if (col == COL_OPTION) {
780 			toggle_sym_value(menu);
781 			gtk_tree_view_expand_row(view, path, TRUE);
782 		}
783 	} else {
784 		if (col == COL_VALUE) {
785 			toggle_sym_value(menu);
786 			gtk_tree_view_expand_row(view, path, TRUE);
787 		} else if (col == COL_NO || col == COL_MOD
788 			   || col == COL_YES) {
789 			change_sym_value(menu, col);
790 			gtk_tree_view_expand_row(view, path, TRUE);
791 		}
792 	}
793 
794 	return FALSE;
795 }
796 
797 /* Key pressed: update choice */
on_treeview2_key_press_event(GtkWidget * widget,GdkEventKey * event,gpointer user_data)798 static gboolean on_treeview2_key_press_event(GtkWidget *widget,
799 					     GdkEventKey *event,
800 					     gpointer user_data)
801 {
802 	GtkTreeView *view = GTK_TREE_VIEW(widget);
803 	GtkTreeModel *model = gtk_tree_view_get_model(view);
804 	GtkTreePath *path;
805 	GtkTreeIter iter;
806 	struct menu *menu;
807 	gint col;
808 
809 	gtk_tree_view_get_cursor(view, &path, NULL);
810 	if (path == NULL)
811 		return FALSE;
812 
813 	if (event->keyval == GDK_KEY_space) {
814 		if (gtk_tree_view_row_expanded(view, path))
815 			gtk_tree_view_collapse_row(view, path);
816 		else
817 			gtk_tree_view_expand_row(view, path, FALSE);
818 		return TRUE;
819 	}
820 
821 	gtk_tree_model_get_iter(model, &iter, path);
822 	gtk_tree_model_get(model, &iter, COL_MENU, &menu, -1);
823 
824 	if (!strcasecmp(event->string, "n"))
825 		col = COL_NO;
826 	else if (!strcasecmp(event->string, "m"))
827 		col = COL_MOD;
828 	else if (!strcasecmp(event->string, "y"))
829 		col = COL_YES;
830 	else
831 		col = -1;
832 	change_sym_value(menu, col);
833 
834 	return FALSE;
835 }
836 
837 
838 /* Row selection changed: update help */
on_treeview2_cursor_changed(GtkTreeView * treeview,gpointer user_data)839 static void on_treeview2_cursor_changed(GtkTreeView *treeview,
840 					gpointer user_data)
841 {
842 	GtkTreeModel *model = gtk_tree_view_get_model(treeview);
843 	GtkTreeSelection *selection;
844 	GtkTreeIter iter;
845 	struct menu *menu;
846 
847 	selection = gtk_tree_view_get_selection(treeview);
848 	if (gtk_tree_selection_get_selected(selection, &model, &iter)) {
849 		gtk_tree_model_get(model, &iter, COL_MENU, &menu, -1);
850 		text_insert_help(menu);
851 	}
852 }
853 
854 
855 /* User click: display sub-tree in the right frame. */
on_treeview1_button_press_event(GtkWidget * widget,GdkEventButton * event,gpointer user_data)856 static gboolean on_treeview1_button_press_event(GtkWidget *widget,
857 						GdkEventButton *event,
858 						gpointer user_data)
859 {
860 	GtkTreeView *view = GTK_TREE_VIEW(widget);
861 	GtkTreeModel *model = gtk_tree_view_get_model(view);
862 	GtkTreePath *path;
863 	GtkTreeIter iter;
864 	struct menu *menu;
865 	gint tx = (gint) event->x;
866 	gint ty = (gint) event->y;
867 
868 	gtk_tree_view_get_path_at_pos(view, tx, ty, &path, NULL, NULL, NULL);
869 	if (path == NULL)
870 		return FALSE;
871 
872 	gtk_tree_model_get_iter(model, &iter, path);
873 	gtk_tree_model_get(model, &iter, COL_MENU, &menu, -1);
874 
875 	if (event->type == GDK_2BUTTON_PRESS)
876 		toggle_sym_value(menu);
877 
878 	selected = menu;
879 
880 	if (menu->type == M_MENU) {
881 		browsed = menu;
882 		recreate_tree();
883 	}
884 
885 	gtk_tree_view_set_cursor(view, path, NULL, FALSE);
886 	gtk_widget_grab_focus(tree2_w);
887 
888 	return FALSE;
889 }
890 
891 /* Display the whole tree (single/split/full view) */
_display_tree(GtkTreeStore * tree,struct menu * menu,GtkTreeIter * parent)892 static void _display_tree(GtkTreeStore *tree, struct menu *menu,
893 			  GtkTreeIter *parent)
894 {
895 	struct menu *child;
896 	GtkTreeIter iter;
897 
898 	for (child = menu->list; child; child = child->next) {
899 		/*
900 		 * REVISIT:
901 		 * menu_finalize() creates empty "if" entries.
902 		 * Do not confuse gtk_tree_model_get(), which would otherwise
903 		 * return "if" menu entry.
904 		 */
905 		if (child->type == M_IF)
906 			continue;
907 
908 		if ((view_mode == SPLIT_VIEW)
909 		    && !(child->flags & MENU_ROOT) && (tree == tree1))
910 			continue;
911 
912 		if ((view_mode == SPLIT_VIEW) && (child->flags & MENU_ROOT)
913 		    && (tree == tree2))
914 			continue;
915 
916 		gtk_tree_store_append(tree, &iter, parent);
917 		set_node(tree, &iter, child);
918 
919 		if (view_mode != SINGLE_VIEW || child->type != M_MENU)
920 			_display_tree(tree, child, &iter);
921 	}
922 }
923 
display_tree(GtkTreeStore * store,struct menu * menu)924 static void display_tree(GtkTreeStore *store, struct menu *menu)
925 {
926 	_display_tree(store, menu, NULL);
927 }
928 
929 /* Recreate the tree store starting at 'browsed' node */
recreate_tree(void)930 static void recreate_tree(void)
931 {
932 	gtk_tree_store_clear(tree2);
933 	display_tree(tree2, browsed);
934 	gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w));
935 }
936 
fixup_rootmenu(struct menu * menu)937 static void fixup_rootmenu(struct menu *menu)
938 {
939 	struct menu *child;
940 	static int menu_cnt = 0;
941 
942 	menu->flags |= MENU_ROOT;
943 	for (child = menu->list; child; child = child->next) {
944 		if (child->prompt && child->prompt->type == P_MENU) {
945 			menu_cnt++;
946 			fixup_rootmenu(child);
947 			menu_cnt--;
948 		} else if (!menu_cnt)
949 			fixup_rootmenu(child);
950 	}
951 }
952 
953 /* Main Window Initialization */
replace_button_icon(GtkWidget * widget,const char * const xpm[])954 static void replace_button_icon(GtkWidget *widget, const char * const xpm[])
955 {
956 	GdkPixbuf *pixbuf;
957 	GtkWidget *image;
958 
959 	pixbuf = gdk_pixbuf_new_from_xpm_data((const char **)xpm);
960 	image = gtk_image_new_from_pixbuf(pixbuf);
961 	g_object_unref(pixbuf);
962 
963 	gtk_widget_show(image);
964 	gtk_tool_button_set_icon_widget(GTK_TOOL_BUTTON(widget), image);
965 }
966 
init_main_window(const gchar * glade_file)967 static void init_main_window(const gchar *glade_file)
968 {
969 	GtkBuilder *builder;
970 	GtkWidget *widget;
971 	GtkTextBuffer *txtbuf;
972 
973 	builder = gtk_builder_new_from_file(glade_file);
974 	if (!builder)
975 		g_error("GUI loading failed !\n");
976 
977 	main_wnd = GTK_WIDGET(gtk_builder_get_object(builder, "window1"));
978 	g_signal_connect(main_wnd, "destroy",
979 			 G_CALLBACK(on_window1_destroy), NULL);
980 	g_signal_connect(main_wnd, "configure-event",
981 			 G_CALLBACK(on_window1_configure), NULL);
982 	g_signal_connect(main_wnd, "delete-event",
983 			 G_CALLBACK(on_window1_delete_event), NULL);
984 
985 	hpaned = GTK_WIDGET(gtk_builder_get_object(builder, "hpaned1"));
986 	vpaned = GTK_WIDGET(gtk_builder_get_object(builder, "vpaned1"));
987 	tree1_w = GTK_WIDGET(gtk_builder_get_object(builder, "treeview1"));
988 	g_signal_connect(tree1_w, "cursor-changed",
989 			 G_CALLBACK(on_treeview2_cursor_changed), NULL);
990 	g_signal_connect(tree1_w, "button-press-event",
991 			 G_CALLBACK(on_treeview1_button_press_event), NULL);
992 	g_signal_connect(tree1_w, "key-press-event",
993 			 G_CALLBACK(on_treeview2_key_press_event), NULL);
994 
995 	tree2_w = GTK_WIDGET(gtk_builder_get_object(builder, "treeview2"));
996 	g_signal_connect(tree2_w, "cursor-changed",
997 			 G_CALLBACK(on_treeview2_cursor_changed), NULL);
998 	g_signal_connect(tree2_w, "button-press-event",
999 			 G_CALLBACK(on_treeview2_button_press_event), NULL);
1000 	g_signal_connect(tree2_w, "key-press-event",
1001 			 G_CALLBACK(on_treeview2_key_press_event), NULL);
1002 
1003 	text_w = GTK_WIDGET(gtk_builder_get_object(builder, "textview3"));
1004 
1005 	/* menubar */
1006 	widget = GTK_WIDGET(gtk_builder_get_object(builder, "load1"));
1007 	g_signal_connect(widget, "activate",
1008 			 G_CALLBACK(on_load1_activate), NULL);
1009 
1010 	save_menu_item = GTK_WIDGET(gtk_builder_get_object(builder, "save1"));
1011 	g_signal_connect(save_menu_item, "activate",
1012 			 G_CALLBACK(on_save_activate), NULL);
1013 
1014 	widget = GTK_WIDGET(gtk_builder_get_object(builder, "save_as1"));
1015 	g_signal_connect(widget, "activate",
1016 			 G_CALLBACK(on_save_as1_activate), NULL);
1017 
1018 	widget = GTK_WIDGET(gtk_builder_get_object(builder, "quit1"));
1019 	g_signal_connect(widget, "activate",
1020 			 G_CALLBACK(on_quit1_activate), NULL);
1021 
1022 	widget = GTK_WIDGET(gtk_builder_get_object(builder, "show_name1"));
1023 	g_signal_connect(widget, "activate",
1024 			 G_CALLBACK(on_show_name1_activate), NULL);
1025 	gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget,
1026 				       show_name);
1027 
1028 	widget = GTK_WIDGET(gtk_builder_get_object(builder, "show_range1"));
1029 	g_signal_connect(widget, "activate",
1030 			 G_CALLBACK(on_show_range1_activate), NULL);
1031 	gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget,
1032 				       show_range);
1033 
1034 	widget = GTK_WIDGET(gtk_builder_get_object(builder, "show_data1"));
1035 	g_signal_connect(widget, "activate",
1036 			 G_CALLBACK(on_show_data1_activate), NULL);
1037 	gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget,
1038 				       show_value);
1039 
1040 	widget = GTK_WIDGET(gtk_builder_get_object(builder, "set_option_mode1"));
1041 	g_signal_connect(widget, "activate",
1042 			 G_CALLBACK(on_set_option_mode1_activate), NULL);
1043 
1044 	widget = GTK_WIDGET(gtk_builder_get_object(builder, "set_option_mode2"));
1045 	g_signal_connect(widget, "activate",
1046 			 G_CALLBACK(on_set_option_mode2_activate), NULL);
1047 
1048 	widget = GTK_WIDGET(gtk_builder_get_object(builder, "set_option_mode3"));
1049 	g_signal_connect(widget, "activate",
1050 			 G_CALLBACK(on_set_option_mode3_activate), NULL);
1051 
1052 	widget = GTK_WIDGET(gtk_builder_get_object(builder, "introduction1"));
1053 	g_signal_connect(widget, "activate",
1054 			 G_CALLBACK(on_introduction1_activate), NULL);
1055 
1056 	widget = GTK_WIDGET(gtk_builder_get_object(builder, "about1"));
1057 	g_signal_connect(widget, "activate",
1058 			 G_CALLBACK(on_about1_activate), NULL);
1059 
1060 	widget = GTK_WIDGET(gtk_builder_get_object(builder, "license1"));
1061 	g_signal_connect(widget, "activate",
1062 			 G_CALLBACK(on_license1_activate), NULL);
1063 
1064 	/* toolbar */
1065 	back_btn = GTK_WIDGET(gtk_builder_get_object(builder, "button1"));
1066 	g_signal_connect(back_btn, "clicked",
1067 			 G_CALLBACK(on_back_clicked), NULL);
1068 	gtk_widget_set_sensitive(back_btn, FALSE);
1069 
1070 	widget = GTK_WIDGET(gtk_builder_get_object(builder, "button2"));
1071 	g_signal_connect(widget, "clicked",
1072 			 G_CALLBACK(on_load_clicked), NULL);
1073 
1074 	save_btn = GTK_WIDGET(gtk_builder_get_object(builder, "button3"));
1075 	g_signal_connect(save_btn, "clicked",
1076 			 G_CALLBACK(on_save_clicked), NULL);
1077 
1078 	single_btn = GTK_WIDGET(gtk_builder_get_object(builder, "button4"));
1079 	g_signal_connect(single_btn, "clicked",
1080 			 G_CALLBACK(on_single_clicked), NULL);
1081 	replace_button_icon(single_btn, xpm_single_view);
1082 
1083 	split_btn = GTK_WIDGET(gtk_builder_get_object(builder, "button5"));
1084 	g_signal_connect(split_btn, "clicked",
1085 			 G_CALLBACK(on_split_clicked), NULL);
1086 	replace_button_icon(split_btn, xpm_split_view);
1087 
1088 	full_btn = GTK_WIDGET(gtk_builder_get_object(builder, "button6"));
1089 	g_signal_connect(full_btn, "clicked",
1090 			 G_CALLBACK(on_full_clicked), NULL);
1091 	replace_button_icon(full_btn, xpm_tree_view);
1092 
1093 	widget = GTK_WIDGET(gtk_builder_get_object(builder, "button7"));
1094 	g_signal_connect(widget, "clicked",
1095 			 G_CALLBACK(on_collapse_clicked), NULL);
1096 
1097 	widget = GTK_WIDGET(gtk_builder_get_object(builder, "button8"));
1098 	g_signal_connect(widget, "clicked",
1099 			 G_CALLBACK(on_expand_clicked), NULL);
1100 
1101 	txtbuf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w));
1102 	tag1 = gtk_text_buffer_create_tag(txtbuf, "mytag1",
1103 					  "foreground", "red",
1104 					  "weight", PANGO_WEIGHT_BOLD,
1105 					  NULL);
1106 	tag2 = gtk_text_buffer_create_tag(txtbuf, "mytag2",
1107 					  /*"style", PANGO_STYLE_OBLIQUE, */
1108 					  NULL);
1109 
1110 	gtk_window_set_title(GTK_WINDOW(main_wnd), rootmenu.prompt->text);
1111 
1112 	gtk_widget_show_all(main_wnd);
1113 
1114 	g_object_unref(builder);
1115 
1116 	conf_set_changed_callback(conf_changed);
1117 }
1118 
visible_func(GtkTreeModel * model,GtkTreeIter * iter,gpointer data)1119 static gboolean visible_func(GtkTreeModel *model, GtkTreeIter  *iter,
1120 			     gpointer data)
1121 {
1122 	struct menu *menu;
1123 
1124 	gtk_tree_model_get(model, iter, COL_MENU, &menu, -1);
1125 
1126 	if (!menu)
1127 		return FALSE;
1128 
1129 	return menu_is_visible(menu) || opt_mode == OPT_ALL ||
1130 		(opt_mode == OPT_PROMPT && menu_has_prompt(menu));
1131 }
1132 
init_left_tree(void)1133 static void init_left_tree(void)
1134 {
1135 	GtkTreeView *view = GTK_TREE_VIEW(tree1_w);
1136 	GtkCellRenderer *renderer;
1137 	GtkTreeSelection *sel;
1138 	GtkTreeViewColumn *column;
1139 	GtkTreeModel *filter;
1140 
1141 	tree1 = gtk_tree_store_new(COL_NUMBER,
1142 				   G_TYPE_STRING, G_TYPE_STRING,
1143 				   G_TYPE_STRING, G_TYPE_STRING,
1144 				   G_TYPE_STRING, G_TYPE_STRING,
1145 				   G_TYPE_POINTER, GDK_TYPE_RGBA,
1146 				   G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF,
1147 				   G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
1148 				   G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
1149 				   G_TYPE_BOOLEAN);
1150 
1151 	filter = gtk_tree_model_filter_new(GTK_TREE_MODEL(tree1), NULL);
1152 
1153 	gtk_tree_model_filter_set_visible_func(GTK_TREE_MODEL_FILTER(filter),
1154 					       visible_func, NULL, NULL);
1155 	gtk_tree_view_set_model(view, filter);
1156 
1157 	column = gtk_tree_view_column_new();
1158 	gtk_tree_view_append_column(view, column);
1159 	gtk_tree_view_column_set_title(column, "Options");
1160 
1161 	renderer = gtk_cell_renderer_toggle_new();
1162 	gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
1163 					renderer, FALSE);
1164 	gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
1165 					    renderer,
1166 					    "active", COL_BTNACT,
1167 					    "inconsistent", COL_BTNINC,
1168 					    "visible", COL_BTNVIS,
1169 					    "radio", COL_BTNRAD, NULL);
1170 	renderer = gtk_cell_renderer_text_new();
1171 	gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
1172 					renderer, FALSE);
1173 	gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
1174 					    renderer,
1175 					    "text", COL_OPTION,
1176 					    "foreground-rgba",
1177 					    COL_COLOR, NULL);
1178 
1179 	sel = gtk_tree_view_get_selection(view);
1180 	gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
1181 }
1182 
init_right_tree(void)1183 static void init_right_tree(void)
1184 {
1185 	GtkTreeView *view = GTK_TREE_VIEW(tree2_w);
1186 	GtkCellRenderer *renderer;
1187 	GtkTreeSelection *sel;
1188 	GtkTreeViewColumn *column;
1189 	GtkTreeModel *filter;
1190 	gint i;
1191 
1192 	tree2 = gtk_tree_store_new(COL_NUMBER,
1193 				   G_TYPE_STRING, G_TYPE_STRING,
1194 				   G_TYPE_STRING, G_TYPE_STRING,
1195 				   G_TYPE_STRING, G_TYPE_STRING,
1196 				   G_TYPE_POINTER, GDK_TYPE_RGBA,
1197 				   G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF,
1198 				   G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
1199 				   G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
1200 				   G_TYPE_BOOLEAN);
1201 
1202 	filter = gtk_tree_model_filter_new(GTK_TREE_MODEL(tree2), NULL);
1203 
1204 	gtk_tree_model_filter_set_visible_func(GTK_TREE_MODEL_FILTER(filter),
1205 					       visible_func, NULL, NULL);
1206 	gtk_tree_view_set_model(view, filter);
1207 
1208 	column = gtk_tree_view_column_new();
1209 	gtk_tree_view_append_column(view, column);
1210 	gtk_tree_view_column_set_title(column, "Options");
1211 
1212 	renderer = gtk_cell_renderer_pixbuf_new();
1213 	gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
1214 					renderer, FALSE);
1215 	gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
1216 					    renderer,
1217 					    "pixbuf", COL_PIXBUF,
1218 					    "visible", COL_PIXVIS, NULL);
1219 	renderer = gtk_cell_renderer_toggle_new();
1220 	gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
1221 					renderer, FALSE);
1222 	gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
1223 					    renderer,
1224 					    "active", COL_BTNACT,
1225 					    "inconsistent", COL_BTNINC,
1226 					    "visible", COL_BTNVIS,
1227 					    "radio", COL_BTNRAD, NULL);
1228 	renderer = gtk_cell_renderer_text_new();
1229 	gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
1230 					renderer, FALSE);
1231 	gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
1232 					    renderer,
1233 					    "text", COL_OPTION,
1234 					    "foreground-rgba",
1235 					    COL_COLOR, NULL);
1236 
1237 	renderer = gtk_cell_renderer_text_new();
1238 	gtk_tree_view_insert_column_with_attributes(view, -1,
1239 						    "Name", renderer,
1240 						    "text", COL_NAME,
1241 						    "foreground-rgba",
1242 						    COL_COLOR, NULL);
1243 	renderer = gtk_cell_renderer_text_new();
1244 	gtk_tree_view_insert_column_with_attributes(view, -1,
1245 						    "N", renderer,
1246 						    "text", COL_NO,
1247 						    "foreground-rgba",
1248 						    COL_COLOR, NULL);
1249 	renderer = gtk_cell_renderer_text_new();
1250 	gtk_tree_view_insert_column_with_attributes(view, -1,
1251 						    "M", renderer,
1252 						    "text", COL_MOD,
1253 						    "foreground-rgba",
1254 						    COL_COLOR, NULL);
1255 	renderer = gtk_cell_renderer_text_new();
1256 	gtk_tree_view_insert_column_with_attributes(view, -1,
1257 						    "Y", renderer,
1258 						    "text", COL_YES,
1259 						    "foreground-rgba",
1260 						    COL_COLOR, NULL);
1261 	renderer = gtk_cell_renderer_text_new();
1262 	gtk_tree_view_insert_column_with_attributes(view, -1,
1263 						    "Value", renderer,
1264 						    "text", COL_VALUE,
1265 						    "editable",
1266 						    COL_EDIT,
1267 						    "foreground-rgba",
1268 						    COL_COLOR, NULL);
1269 	g_signal_connect(G_OBJECT(renderer), "edited",
1270 			 G_CALLBACK(renderer_edited), tree2_w);
1271 
1272 	pix_menu = gdk_pixbuf_new_from_xpm_data((const char **)xpm_menu);
1273 
1274 	for (i = 0; i < COL_VALUE; i++) {
1275 		column = gtk_tree_view_get_column(view, i);
1276 		gtk_tree_view_column_set_resizable(column, TRUE);
1277 	}
1278 
1279 	sel = gtk_tree_view_get_selection(view);
1280 	gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
1281 }
1282 
1283 /* Main */
main(int ac,char * av[])1284 int main(int ac, char *av[])
1285 {
1286 	const char *name;
1287 	char *env;
1288 	gchar *glade_file;
1289 
1290 	/* GTK stuffs */
1291 	gtk_init(&ac, &av);
1292 
1293 	/* Determine GUI path */
1294 	env = getenv(SRCTREE);
1295 	if (env)
1296 		glade_file = g_strconcat(env, "/scripts/kconfig/gconf.ui", NULL);
1297 	else if (av[0][0] == '/')
1298 		glade_file = g_strconcat(av[0], ".ui", NULL);
1299 	else
1300 		glade_file = g_strconcat(g_get_current_dir(), "/", av[0], ".ui", NULL);
1301 
1302 	/* Conf stuffs */
1303 	if (ac > 1 && av[1][0] == '-') {
1304 		switch (av[1][1]) {
1305 		case 'a':
1306 			//showAll = 1;
1307 			break;
1308 		case 's':
1309 			conf_set_message_callback(NULL);
1310 			break;
1311 		case 'h':
1312 		case '?':
1313 			printf("%s [-s] <config>\n", av[0]);
1314 			exit(0);
1315 		}
1316 		name = av[2];
1317 	} else
1318 		name = av[1];
1319 
1320 	conf_parse(name);
1321 	fixup_rootmenu(&rootmenu);
1322 
1323 	/* Load the interface and connect signals */
1324 	init_main_window(glade_file);
1325 	init_left_tree();
1326 	init_right_tree();
1327 
1328 	conf_read(NULL);
1329 
1330 	set_view_mode(view_mode);
1331 
1332 	gtk_main();
1333 
1334 	return 0;
1335 }
1336