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