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