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