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