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