ia64/linux-2.6.18-xen.hg

view scripts/kconfig/gconf.c @ 897:329ea0ccb344

balloon: try harder to balloon up under memory pressure.

Currently if the balloon driver is unable to increase the guest's
reservation it assumes the failure was due to reaching its full
allocation, gives up on the ballooning operation and records the limit
it reached as the "hard limit". The driver will not try again until
the target is set again (even to the same value).

However it is possible that ballooning has in fact failed due to
memory pressure in the host and therefore it is desirable to keep
attempting to reach the target in case memory becomes available. The
most likely scenario is that some guests are ballooning down while
others are ballooning up and therefore there is temporary memory
pressure while things stabilise. You would not expect a well behaved
toolstack to ask a domain to balloon to more than its allocation nor
would you expect it to deliberately over-commit memory by setting
balloon targets which exceed the total host memory.

This patch drops the concept of a hard limit and causes the balloon
driver to retry increasing the reservation on a timer in the same
manner as when decreasing the reservation.

Also if we partially succeed in increasing the reservation
(i.e. receive less pages than we asked for) then we may as well keep
those pages rather than returning them to Xen.

Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Fri Jun 05 14:01:20 2009 +0100 (2009-06-05)
parents 831230e53067
children
line source
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 */
9 #ifdef HAVE_CONFIG_H
10 # include <config.h>
11 #endif
13 #include "lkc.h"
14 #include "images.c"
16 #include <glade/glade.h>
17 #include <gtk/gtk.h>
18 #include <glib.h>
19 #include <gdk/gdkkeysyms.h>
21 #include <stdio.h>
22 #include <string.h>
23 #include <unistd.h>
24 #include <time.h>
25 #include <stdlib.h>
27 //#define DEBUG
29 enum {
30 SINGLE_VIEW, SPLIT_VIEW, FULL_VIEW
31 };
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;
41 static gboolean config_changed = FALSE;
43 static char nohelp_text[] =
44 N_("Sorry, no help available for this option yet.\n");
46 GtkWidget *main_wnd = NULL;
47 GtkWidget *tree1_w = NULL; // left frame
48 GtkWidget *tree2_w = NULL; // right frame
49 GtkWidget *text_w = NULL;
50 GtkWidget *hpaned = NULL;
51 GtkWidget *vpaned = NULL;
52 GtkWidget *back_btn = NULL;
54 GtkTextTag *tag1, *tag2;
55 GdkColor color;
57 GtkTreeStore *tree1, *tree2, *tree;
58 GtkTreeModel *model1, *model2;
59 static GtkTreeIter *parents[256];
60 static gint indent;
62 static struct menu *current; // current node for SINGLE view
63 static struct menu *browsed; // browsed node for SPLIT view
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 };
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);
80 /* Helping/Debugging Functions */
83 const char *dbg_print_stype(int val)
84 {
85 static char buf[256];
87 bzero(buf, 256);
89 if (val == S_UNKNOWN)
90 strcpy(buf, "unknown");
91 if (val == S_BOOLEAN)
92 strcpy(buf, "boolean");
93 if (val == S_TRISTATE)
94 strcpy(buf, "tristate");
95 if (val == S_INT)
96 strcpy(buf, "int");
97 if (val == S_HEX)
98 strcpy(buf, "hex");
99 if (val == S_STRING)
100 strcpy(buf, "string");
101 if (val == S_OTHER)
102 strcpy(buf, "other");
104 #ifdef DEBUG
105 printf("%s", buf);
106 #endif
108 return buf;
109 }
111 const char *dbg_print_flags(int val)
112 {
113 static char buf[256];
115 bzero(buf, 256);
117 if (val & SYMBOL_CONST)
118 strcat(buf, "const/");
119 if (val & SYMBOL_CHECK)
120 strcat(buf, "check/");
121 if (val & SYMBOL_CHOICE)
122 strcat(buf, "choice/");
123 if (val & SYMBOL_CHOICEVAL)
124 strcat(buf, "choiceval/");
125 if (val & SYMBOL_PRINTED)
126 strcat(buf, "printed/");
127 if (val & SYMBOL_VALID)
128 strcat(buf, "valid/");
129 if (val & SYMBOL_OPTIONAL)
130 strcat(buf, "optional/");
131 if (val & SYMBOL_WRITE)
132 strcat(buf, "write/");
133 if (val & SYMBOL_CHANGED)
134 strcat(buf, "changed/");
135 if (val & SYMBOL_AUTO)
136 strcat(buf, "auto/");
138 buf[strlen(buf) - 1] = '\0';
139 #ifdef DEBUG
140 printf("%s", buf);
141 #endif
143 return buf;
144 }
146 const char *dbg_print_ptype(int val)
147 {
148 static char buf[256];
150 bzero(buf, 256);
152 if (val == P_UNKNOWN)
153 strcpy(buf, "unknown");
154 if (val == P_PROMPT)
155 strcpy(buf, "prompt");
156 if (val == P_COMMENT)
157 strcpy(buf, "comment");
158 if (val == P_MENU)
159 strcpy(buf, "menu");
160 if (val == P_DEFAULT)
161 strcpy(buf, "default");
162 if (val == P_CHOICE)
163 strcpy(buf, "choice");
165 #ifdef DEBUG
166 printf("%s", buf);
167 #endif
169 return buf;
170 }
173 void replace_button_icon(GladeXML * xml, GdkDrawable * window,
174 GtkStyle * style, gchar * btn_name, gchar ** xpm)
175 {
176 GdkPixmap *pixmap;
177 GdkBitmap *mask;
178 GtkToolButton *button;
179 GtkWidget *image;
181 pixmap = gdk_pixmap_create_from_xpm_d(window, &mask,
182 &style->bg[GTK_STATE_NORMAL],
183 xpm);
185 button = GTK_TOOL_BUTTON(glade_xml_get_widget(xml, btn_name));
186 image = gtk_image_new_from_pixmap(pixmap, mask);
187 gtk_widget_show(image);
188 gtk_tool_button_set_icon_widget(button, image);
189 }
191 /* Main Window Initialization */
192 void init_main_window(const gchar * glade_file)
193 {
194 GladeXML *xml;
195 GtkWidget *widget;
196 GtkTextBuffer *txtbuf;
197 char title[256];
198 GtkStyle *style;
200 xml = glade_xml_new(glade_file, "window1", NULL);
201 if (!xml)
202 g_error(_("GUI loading failed !\n"));
203 glade_xml_signal_autoconnect(xml);
205 main_wnd = glade_xml_get_widget(xml, "window1");
206 hpaned = glade_xml_get_widget(xml, "hpaned1");
207 vpaned = glade_xml_get_widget(xml, "vpaned1");
208 tree1_w = glade_xml_get_widget(xml, "treeview1");
209 tree2_w = glade_xml_get_widget(xml, "treeview2");
210 text_w = glade_xml_get_widget(xml, "textview3");
212 back_btn = glade_xml_get_widget(xml, "button1");
213 gtk_widget_set_sensitive(back_btn, FALSE);
215 widget = glade_xml_get_widget(xml, "show_name1");
216 gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget,
217 show_name);
219 widget = glade_xml_get_widget(xml, "show_range1");
220 gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget,
221 show_range);
223 widget = glade_xml_get_widget(xml, "show_data1");
224 gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget,
225 show_value);
227 style = gtk_widget_get_style(main_wnd);
228 widget = glade_xml_get_widget(xml, "toolbar1");
230 #if 0 /* Use stock Gtk icons instead */
231 replace_button_icon(xml, main_wnd->window, style,
232 "button1", (gchar **) xpm_back);
233 replace_button_icon(xml, main_wnd->window, style,
234 "button2", (gchar **) xpm_load);
235 replace_button_icon(xml, main_wnd->window, style,
236 "button3", (gchar **) xpm_save);
237 #endif
238 replace_button_icon(xml, main_wnd->window, style,
239 "button4", (gchar **) xpm_single_view);
240 replace_button_icon(xml, main_wnd->window, style,
241 "button5", (gchar **) xpm_split_view);
242 replace_button_icon(xml, main_wnd->window, style,
243 "button6", (gchar **) xpm_tree_view);
245 #if 0
246 switch (view_mode) {
247 case SINGLE_VIEW:
248 widget = glade_xml_get_widget(xml, "button4");
249 g_signal_emit_by_name(widget, "clicked");
250 break;
251 case SPLIT_VIEW:
252 widget = glade_xml_get_widget(xml, "button5");
253 g_signal_emit_by_name(widget, "clicked");
254 break;
255 case FULL_VIEW:
256 widget = glade_xml_get_widget(xml, "button6");
257 g_signal_emit_by_name(widget, "clicked");
258 break;
259 }
260 #endif
261 txtbuf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w));
262 tag1 = gtk_text_buffer_create_tag(txtbuf, "mytag1",
263 "foreground", "red",
264 "weight", PANGO_WEIGHT_BOLD,
265 NULL);
266 tag2 = gtk_text_buffer_create_tag(txtbuf, "mytag2",
267 /*"style", PANGO_STYLE_OBLIQUE, */
268 NULL);
270 sprintf(title, _("Linux Kernel v%s Configuration"),
271 getenv("KERNELVERSION"));
272 gtk_window_set_title(GTK_WINDOW(main_wnd), title);
274 gtk_widget_show(main_wnd);
275 }
277 void init_tree_model(void)
278 {
279 gint i;
281 tree = tree2 = gtk_tree_store_new(COL_NUMBER,
282 G_TYPE_STRING, G_TYPE_STRING,
283 G_TYPE_STRING, G_TYPE_STRING,
284 G_TYPE_STRING, G_TYPE_STRING,
285 G_TYPE_POINTER, GDK_TYPE_COLOR,
286 G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF,
287 G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
288 G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
289 G_TYPE_BOOLEAN);
290 model2 = GTK_TREE_MODEL(tree2);
292 for (parents[0] = NULL, i = 1; i < 256; i++)
293 parents[i] = (GtkTreeIter *) g_malloc(sizeof(GtkTreeIter));
295 tree1 = gtk_tree_store_new(COL_NUMBER,
296 G_TYPE_STRING, G_TYPE_STRING,
297 G_TYPE_STRING, G_TYPE_STRING,
298 G_TYPE_STRING, G_TYPE_STRING,
299 G_TYPE_POINTER, GDK_TYPE_COLOR,
300 G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF,
301 G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
302 G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
303 G_TYPE_BOOLEAN);
304 model1 = GTK_TREE_MODEL(tree1);
305 }
307 void init_left_tree(void)
308 {
309 GtkTreeView *view = GTK_TREE_VIEW(tree1_w);
310 GtkCellRenderer *renderer;
311 GtkTreeSelection *sel;
312 GtkTreeViewColumn *column;
314 gtk_tree_view_set_model(view, model1);
315 gtk_tree_view_set_headers_visible(view, TRUE);
316 gtk_tree_view_set_rules_hint(view, FALSE);
318 column = gtk_tree_view_column_new();
319 gtk_tree_view_append_column(view, column);
320 gtk_tree_view_column_set_title(column, _("Options"));
322 renderer = gtk_cell_renderer_toggle_new();
323 gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
324 renderer, FALSE);
325 gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
326 renderer,
327 "active", COL_BTNACT,
328 "inconsistent", COL_BTNINC,
329 "visible", COL_BTNVIS,
330 "radio", COL_BTNRAD, NULL);
331 renderer = gtk_cell_renderer_text_new();
332 gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
333 renderer, FALSE);
334 gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
335 renderer,
336 "text", COL_OPTION,
337 "foreground-gdk",
338 COL_COLOR, NULL);
340 sel = gtk_tree_view_get_selection(view);
341 gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
342 gtk_widget_realize(tree1_w);
343 }
345 static void renderer_edited(GtkCellRendererText * cell,
346 const gchar * path_string,
347 const gchar * new_text, gpointer user_data);
348 static void renderer_toggled(GtkCellRendererToggle * cellrenderertoggle,
349 gchar * arg1, gpointer user_data);
351 void init_right_tree(void)
352 {
353 GtkTreeView *view = GTK_TREE_VIEW(tree2_w);
354 GtkCellRenderer *renderer;
355 GtkTreeSelection *sel;
356 GtkTreeViewColumn *column;
357 gint i;
359 gtk_tree_view_set_model(view, model2);
360 gtk_tree_view_set_headers_visible(view, TRUE);
361 gtk_tree_view_set_rules_hint(view, FALSE);
363 column = gtk_tree_view_column_new();
364 gtk_tree_view_append_column(view, column);
365 gtk_tree_view_column_set_title(column, _("Options"));
367 renderer = gtk_cell_renderer_pixbuf_new();
368 gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
369 renderer, FALSE);
370 gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
371 renderer,
372 "pixbuf", COL_PIXBUF,
373 "visible", COL_PIXVIS, NULL);
374 renderer = gtk_cell_renderer_toggle_new();
375 gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
376 renderer, FALSE);
377 gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
378 renderer,
379 "active", COL_BTNACT,
380 "inconsistent", COL_BTNINC,
381 "visible", COL_BTNVIS,
382 "radio", COL_BTNRAD, NULL);
383 /*g_signal_connect(G_OBJECT(renderer), "toggled",
384 G_CALLBACK(renderer_toggled), NULL); */
385 renderer = gtk_cell_renderer_text_new();
386 gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
387 renderer, FALSE);
388 gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
389 renderer,
390 "text", COL_OPTION,
391 "foreground-gdk",
392 COL_COLOR, NULL);
394 renderer = gtk_cell_renderer_text_new();
395 gtk_tree_view_insert_column_with_attributes(view, -1,
396 _("Name"), renderer,
397 "text", COL_NAME,
398 "foreground-gdk",
399 COL_COLOR, NULL);
400 renderer = gtk_cell_renderer_text_new();
401 gtk_tree_view_insert_column_with_attributes(view, -1,
402 "N", renderer,
403 "text", COL_NO,
404 "foreground-gdk",
405 COL_COLOR, NULL);
406 renderer = gtk_cell_renderer_text_new();
407 gtk_tree_view_insert_column_with_attributes(view, -1,
408 "M", renderer,
409 "text", COL_MOD,
410 "foreground-gdk",
411 COL_COLOR, NULL);
412 renderer = gtk_cell_renderer_text_new();
413 gtk_tree_view_insert_column_with_attributes(view, -1,
414 "Y", renderer,
415 "text", COL_YES,
416 "foreground-gdk",
417 COL_COLOR, NULL);
418 renderer = gtk_cell_renderer_text_new();
419 gtk_tree_view_insert_column_with_attributes(view, -1,
420 _("Value"), renderer,
421 "text", COL_VALUE,
422 "editable",
423 COL_EDIT,
424 "foreground-gdk",
425 COL_COLOR, NULL);
426 g_signal_connect(G_OBJECT(renderer), "edited",
427 G_CALLBACK(renderer_edited), NULL);
429 column = gtk_tree_view_get_column(view, COL_NAME);
430 gtk_tree_view_column_set_visible(column, show_name);
431 column = gtk_tree_view_get_column(view, COL_NO);
432 gtk_tree_view_column_set_visible(column, show_range);
433 column = gtk_tree_view_get_column(view, COL_MOD);
434 gtk_tree_view_column_set_visible(column, show_range);
435 column = gtk_tree_view_get_column(view, COL_YES);
436 gtk_tree_view_column_set_visible(column, show_range);
437 column = gtk_tree_view_get_column(view, COL_VALUE);
438 gtk_tree_view_column_set_visible(column, show_value);
440 if (resizeable) {
441 for (i = 0; i < COL_VALUE; i++) {
442 column = gtk_tree_view_get_column(view, i);
443 gtk_tree_view_column_set_resizable(column, TRUE);
444 }
445 }
447 sel = gtk_tree_view_get_selection(view);
448 gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
449 }
452 /* Utility Functions */
455 static void text_insert_help(struct menu *menu)
456 {
457 GtkTextBuffer *buffer;
458 GtkTextIter start, end;
459 const char *prompt = menu_get_prompt(menu);
460 gchar *name;
461 const char *help = _(nohelp_text);
463 if (!menu->sym)
464 help = "";
465 else if (menu->sym->help)
466 help = _(menu->sym->help);
468 if (menu->sym && menu->sym->name)
469 name = g_strdup_printf(_(menu->sym->name));
470 else
471 name = g_strdup("");
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);
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 }
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;
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);
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 }
513 /* Main Windows Callbacks */
515 void on_save1_activate(GtkMenuItem * menuitem, 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;
522 if (config_changed == FALSE)
523 return FALSE;
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);
539 label = gtk_label_new(_("\nSave configuration ?\n"));
540 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), label);
541 gtk_widget_show(label);
543 result = gtk_dialog_run(GTK_DIALOG(dialog));
544 switch (result) {
545 case GTK_RESPONSE_YES:
546 on_save1_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 }
557 return FALSE;
558 }
561 void on_window1_destroy(GtkObject * object, gpointer user_data)
562 {
563 gtk_main_quit();
564 }
567 void
568 on_window1_size_request(GtkWidget * widget,
569 GtkRequisition * requisition, gpointer user_data)
570 {
571 static gint old_h;
572 gint w, h;
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);
579 if (h == old_h)
580 return;
581 old_h = h;
583 gtk_paned_set_position(GTK_PANED(vpaned), 2 * h / 3);
584 }
587 /* Menu & Toolbar Callbacks */
590 static void
591 load_filename(GtkFileSelection * file_selector, gpointer user_data)
592 {
593 const gchar *fn;
595 fn = gtk_file_selection_get_filename(GTK_FILE_SELECTION
596 (user_data));
598 if (conf_read(fn))
599 text_insert_msg(_("Error"), _("Unable to load configuration !"));
600 else
601 display_tree(&rootmenu);
602 }
604 void on_load1_activate(GtkMenuItem * menuitem, gpointer user_data)
605 {
606 GtkWidget *fs;
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 }
624 void on_save1_activate(GtkMenuItem * menuitem, gpointer user_data)
625 {
626 if (conf_write(NULL))
627 text_insert_msg(_("Error"), _("Unable to save configuration !"));
629 config_changed = FALSE;
630 }
633 static void
634 store_filename(GtkFileSelection * file_selector, gpointer user_data)
635 {
636 const gchar *fn;
638 fn = gtk_file_selection_get_filename(GTK_FILE_SELECTION
639 (user_data));
641 if (conf_write(fn))
642 text_insert_msg(_("Error"), _("Unable to save configuration !"));
644 gtk_widget_destroy(GTK_WIDGET(user_data));
645 }
647 void on_save_as1_activate(GtkMenuItem * menuitem, gpointer user_data)
648 {
649 GtkWidget *fs;
651 fs = gtk_file_selection_new(_("Save file as..."));
652 g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs)->ok_button),
653 "clicked",
654 G_CALLBACK(store_filename), (gpointer) fs);
655 g_signal_connect_swapped(GTK_OBJECT
656 (GTK_FILE_SELECTION(fs)->ok_button),
657 "clicked", G_CALLBACK(gtk_widget_destroy),
658 (gpointer) fs);
659 g_signal_connect_swapped(GTK_OBJECT
660 (GTK_FILE_SELECTION(fs)->cancel_button),
661 "clicked", G_CALLBACK(gtk_widget_destroy),
662 (gpointer) fs);
663 gtk_widget_show(fs);
664 }
667 void on_quit1_activate(GtkMenuItem * menuitem, gpointer user_data)
668 {
669 if (!on_window1_delete_event(NULL, NULL, NULL))
670 gtk_widget_destroy(GTK_WIDGET(main_wnd));
671 }
674 void on_show_name1_activate(GtkMenuItem * menuitem, gpointer user_data)
675 {
676 GtkTreeViewColumn *col;
678 show_name = GTK_CHECK_MENU_ITEM(menuitem)->active;
679 col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_NAME);
680 if (col)
681 gtk_tree_view_column_set_visible(col, show_name);
682 }
685 void on_show_range1_activate(GtkMenuItem * menuitem, gpointer user_data)
686 {
687 GtkTreeViewColumn *col;
689 show_range = GTK_CHECK_MENU_ITEM(menuitem)->active;
690 col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_NO);
691 if (col)
692 gtk_tree_view_column_set_visible(col, show_range);
693 col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_MOD);
694 if (col)
695 gtk_tree_view_column_set_visible(col, show_range);
696 col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_YES);
697 if (col)
698 gtk_tree_view_column_set_visible(col, show_range);
700 }
703 void on_show_data1_activate(GtkMenuItem * menuitem, gpointer user_data)
704 {
705 GtkTreeViewColumn *col;
707 show_value = GTK_CHECK_MENU_ITEM(menuitem)->active;
708 col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_VALUE);
709 if (col)
710 gtk_tree_view_column_set_visible(col, show_value);
711 }
714 void
715 on_show_all_options1_activate(GtkMenuItem * menuitem, gpointer user_data)
716 {
717 show_all = GTK_CHECK_MENU_ITEM(menuitem)->active;
719 gtk_tree_store_clear(tree2);
720 display_tree(&rootmenu); // instead of update_tree to speed-up
721 }
724 void
725 on_show_debug_info1_activate(GtkMenuItem * menuitem, gpointer user_data)
726 {
727 show_debug = GTK_CHECK_MENU_ITEM(menuitem)->active;
728 update_tree(&rootmenu, NULL);
729 }
732 void on_introduction1_activate(GtkMenuItem * menuitem, gpointer user_data)
733 {
734 GtkWidget *dialog;
735 const gchar *intro_text = _(
736 "Welcome to gkc, the GTK+ graphical kernel configuration tool\n"
737 "for Linux.\n"
738 "For each option, a blank box indicates the feature is disabled, a\n"
739 "check indicates it is enabled, and a dot indicates that it is to\n"
740 "be compiled as a module. Clicking on the box will cycle through the three states.\n"
741 "\n"
742 "If you do not see an option (e.g., a device driver) that you\n"
743 "believe should be present, try turning on Show All Options\n"
744 "under the Options menu.\n"
745 "Although there is no cross reference yet to help you figure out\n"
746 "what other options must be enabled to support the option you\n"
747 "are interested in, you can still view the help of a grayed-out\n"
748 "option.\n"
749 "\n"
750 "Toggling Show Debug Info under the Options menu will show \n"
751 "the dependencies, which you can then match by examining other options.");
753 dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
754 GTK_DIALOG_DESTROY_WITH_PARENT,
755 GTK_MESSAGE_INFO,
756 GTK_BUTTONS_CLOSE, intro_text);
757 g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
758 G_CALLBACK(gtk_widget_destroy),
759 GTK_OBJECT(dialog));
760 gtk_widget_show_all(dialog);
761 }
764 void on_about1_activate(GtkMenuItem * menuitem, gpointer user_data)
765 {
766 GtkWidget *dialog;
767 const gchar *about_text =
768 _("gkc is copyright (c) 2002 Romain Lievin <roms@lpg.ticalc.org>.\n"
769 "Based on the source code from Roman Zippel.\n");
771 dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
772 GTK_DIALOG_DESTROY_WITH_PARENT,
773 GTK_MESSAGE_INFO,
774 GTK_BUTTONS_CLOSE, about_text);
775 g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
776 G_CALLBACK(gtk_widget_destroy),
777 GTK_OBJECT(dialog));
778 gtk_widget_show_all(dialog);
779 }
782 void on_license1_activate(GtkMenuItem * menuitem, gpointer user_data)
783 {
784 GtkWidget *dialog;
785 const gchar *license_text =
786 _("gkc is released under the terms of the GNU GPL v2.\n"
787 "For more information, please see the source code or\n"
788 "visit http://www.fsf.org/licenses/licenses.html\n");
790 dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
791 GTK_DIALOG_DESTROY_WITH_PARENT,
792 GTK_MESSAGE_INFO,
793 GTK_BUTTONS_CLOSE, license_text);
794 g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
795 G_CALLBACK(gtk_widget_destroy),
796 GTK_OBJECT(dialog));
797 gtk_widget_show_all(dialog);
798 }
801 void on_back_clicked(GtkButton * button, gpointer user_data)
802 {
803 enum prop_type ptype;
805 current = current->parent;
806 ptype = current->prompt ? current->prompt->type : P_UNKNOWN;
807 if (ptype != P_MENU)
808 current = current->parent;
809 display_tree_part();
811 if (current == &rootmenu)
812 gtk_widget_set_sensitive(back_btn, FALSE);
813 }
816 void on_load_clicked(GtkButton * button, gpointer user_data)
817 {
818 on_load1_activate(NULL, user_data);
819 }
822 void on_save_clicked(GtkButton * button, gpointer user_data)
823 {
824 on_save1_activate(NULL, user_data);
825 }
828 void on_single_clicked(GtkButton * button, gpointer user_data)
829 {
830 view_mode = SINGLE_VIEW;
831 gtk_paned_set_position(GTK_PANED(hpaned), 0);
832 gtk_widget_hide(tree1_w);
833 current = &rootmenu;
834 display_tree_part();
835 }
838 void on_split_clicked(GtkButton * button, gpointer user_data)
839 {
840 gint w, h;
841 view_mode = SPLIT_VIEW;
842 gtk_widget_show(tree1_w);
843 gtk_window_get_default_size(GTK_WINDOW(main_wnd), &w, &h);
844 gtk_paned_set_position(GTK_PANED(hpaned), w / 2);
845 if (tree2)
846 gtk_tree_store_clear(tree2);
847 display_list();
849 /* Disable back btn, like in full mode. */
850 gtk_widget_set_sensitive(back_btn, FALSE);
851 }
854 void on_full_clicked(GtkButton * button, gpointer user_data)
855 {
856 view_mode = FULL_VIEW;
857 gtk_paned_set_position(GTK_PANED(hpaned), 0);
858 gtk_widget_hide(tree1_w);
859 if (tree2)
860 gtk_tree_store_clear(tree2);
861 display_tree(&rootmenu);
862 gtk_widget_set_sensitive(back_btn, FALSE);
863 }
866 void on_collapse_clicked(GtkButton * button, gpointer user_data)
867 {
868 gtk_tree_view_collapse_all(GTK_TREE_VIEW(tree2_w));
869 }
872 void on_expand_clicked(GtkButton * button, gpointer user_data)
873 {
874 gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w));
875 }
878 /* CTree Callbacks */
880 /* Change hex/int/string value in the cell */
881 static void renderer_edited(GtkCellRendererText * cell,
882 const gchar * path_string,
883 const gchar * new_text, gpointer user_data)
884 {
885 GtkTreePath *path = gtk_tree_path_new_from_string(path_string);
886 GtkTreeIter iter;
887 const char *old_def, *new_def;
888 struct menu *menu;
889 struct symbol *sym;
891 if (!gtk_tree_model_get_iter(model2, &iter, path))
892 return;
894 gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
895 sym = menu->sym;
897 gtk_tree_model_get(model2, &iter, COL_VALUE, &old_def, -1);
898 new_def = new_text;
900 sym_set_string_value(sym, new_def);
902 config_changed = TRUE;
903 update_tree(&rootmenu, NULL);
905 gtk_tree_path_free(path);
906 }
908 /* Change the value of a symbol and update the tree */
909 static void change_sym_value(struct menu *menu, gint col)
910 {
911 struct symbol *sym = menu->sym;
912 tristate oldval, newval;
914 if (!sym)
915 return;
917 if (col == COL_NO)
918 newval = no;
919 else if (col == COL_MOD)
920 newval = mod;
921 else if (col == COL_YES)
922 newval = yes;
923 else
924 return;
926 switch (sym_get_type(sym)) {
927 case S_BOOLEAN:
928 case S_TRISTATE:
929 oldval = sym_get_tristate_value(sym);
930 if (!sym_tristate_within_range(sym, newval))
931 newval = yes;
932 sym_set_tristate_value(sym, newval);
933 config_changed = TRUE;
934 if (view_mode == FULL_VIEW)
935 update_tree(&rootmenu, NULL);
936 else if (view_mode == SPLIT_VIEW) {
937 update_tree(browsed, NULL);
938 display_list();
939 }
940 else if (view_mode == SINGLE_VIEW)
941 display_tree_part(); //fixme: keep exp/coll
942 break;
943 case S_INT:
944 case S_HEX:
945 case S_STRING:
946 default:
947 break;
948 }
949 }
951 static void toggle_sym_value(struct menu *menu)
952 {
953 if (!menu->sym)
954 return;
956 sym_toggle_tristate_value(menu->sym);
957 if (view_mode == FULL_VIEW)
958 update_tree(&rootmenu, NULL);
959 else if (view_mode == SPLIT_VIEW) {
960 update_tree(browsed, NULL);
961 display_list();
962 }
963 else if (view_mode == SINGLE_VIEW)
964 display_tree_part(); //fixme: keep exp/coll
965 }
967 static void renderer_toggled(GtkCellRendererToggle * cell,
968 gchar * path_string, gpointer user_data)
969 {
970 GtkTreePath *path, *sel_path = NULL;
971 GtkTreeIter iter, sel_iter;
972 GtkTreeSelection *sel;
973 struct menu *menu;
975 path = gtk_tree_path_new_from_string(path_string);
976 if (!gtk_tree_model_get_iter(model2, &iter, path))
977 return;
979 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree2_w));
980 if (gtk_tree_selection_get_selected(sel, NULL, &sel_iter))
981 sel_path = gtk_tree_model_get_path(model2, &sel_iter);
982 if (!sel_path)
983 goto out1;
984 if (gtk_tree_path_compare(path, sel_path))
985 goto out2;
987 gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
988 toggle_sym_value(menu);
990 out2:
991 gtk_tree_path_free(sel_path);
992 out1:
993 gtk_tree_path_free(path);
994 }
996 static gint column2index(GtkTreeViewColumn * column)
997 {
998 gint i;
1000 for (i = 0; i < COL_NUMBER; i++) {
1001 GtkTreeViewColumn *col;
1003 col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), i);
1004 if (col == column)
1005 return i;
1008 return -1;
1012 /* User click: update choice (full) or goes down (single) */
1013 gboolean
1014 on_treeview2_button_press_event(GtkWidget * widget,
1015 GdkEventButton * event, gpointer user_data)
1017 GtkTreeView *view = GTK_TREE_VIEW(widget);
1018 GtkTreePath *path;
1019 GtkTreeViewColumn *column;
1020 GtkTreeIter iter;
1021 struct menu *menu;
1022 gint col;
1024 #if GTK_CHECK_VERSION(2,1,4) // bug in ctree with earlier version of GTK
1025 gint tx = (gint) event->x;
1026 gint ty = (gint) event->y;
1027 gint cx, cy;
1029 gtk_tree_view_get_path_at_pos(view, tx, ty, &path, &column, &cx,
1030 &cy);
1031 #else
1032 gtk_tree_view_get_cursor(view, &path, &column);
1033 #endif
1034 if (path == NULL)
1035 return FALSE;
1037 if (!gtk_tree_model_get_iter(model2, &iter, path))
1038 return FALSE;
1039 gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
1041 col = column2index(column);
1042 if (event->type == GDK_2BUTTON_PRESS) {
1043 enum prop_type ptype;
1044 ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
1046 if (ptype == P_MENU && view_mode != FULL_VIEW && col == COL_OPTION) {
1047 // goes down into menu
1048 current = menu;
1049 display_tree_part();
1050 gtk_widget_set_sensitive(back_btn, TRUE);
1051 } else if ((col == COL_OPTION)) {
1052 toggle_sym_value(menu);
1053 gtk_tree_view_expand_row(view, path, TRUE);
1055 } else {
1056 if (col == COL_VALUE) {
1057 toggle_sym_value(menu);
1058 gtk_tree_view_expand_row(view, path, TRUE);
1059 } else if (col == COL_NO || col == COL_MOD
1060 || col == COL_YES) {
1061 change_sym_value(menu, col);
1062 gtk_tree_view_expand_row(view, path, TRUE);
1066 return FALSE;
1069 /* Key pressed: update choice */
1070 gboolean
1071 on_treeview2_key_press_event(GtkWidget * widget,
1072 GdkEventKey * event, gpointer user_data)
1074 GtkTreeView *view = GTK_TREE_VIEW(widget);
1075 GtkTreePath *path;
1076 GtkTreeViewColumn *column;
1077 GtkTreeIter iter;
1078 struct menu *menu;
1079 gint col;
1081 gtk_tree_view_get_cursor(view, &path, &column);
1082 if (path == NULL)
1083 return FALSE;
1085 if (event->keyval == GDK_space) {
1086 if (gtk_tree_view_row_expanded(view, path))
1087 gtk_tree_view_collapse_row(view, path);
1088 else
1089 gtk_tree_view_expand_row(view, path, FALSE);
1090 return TRUE;
1092 if (event->keyval == GDK_KP_Enter) {
1094 if (widget == tree1_w)
1095 return FALSE;
1097 gtk_tree_model_get_iter(model2, &iter, path);
1098 gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
1100 if (!strcasecmp(event->string, "n"))
1101 col = COL_NO;
1102 else if (!strcasecmp(event->string, "m"))
1103 col = COL_MOD;
1104 else if (!strcasecmp(event->string, "y"))
1105 col = COL_YES;
1106 else
1107 col = -1;
1108 change_sym_value(menu, col);
1110 return FALSE;
1114 /* Row selection changed: update help */
1115 void
1116 on_treeview2_cursor_changed(GtkTreeView * treeview, gpointer user_data)
1118 GtkTreeSelection *selection;
1119 GtkTreeIter iter;
1120 struct menu *menu;
1122 selection = gtk_tree_view_get_selection(treeview);
1123 if (gtk_tree_selection_get_selected(selection, &model2, &iter)) {
1124 gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
1125 text_insert_help(menu);
1130 /* User click: display sub-tree in the right frame. */
1131 gboolean
1132 on_treeview1_button_press_event(GtkWidget * widget,
1133 GdkEventButton * event, gpointer user_data)
1135 GtkTreeView *view = GTK_TREE_VIEW(widget);
1136 GtkTreePath *path;
1137 GtkTreeViewColumn *column;
1138 GtkTreeIter iter;
1139 struct menu *menu;
1141 gint tx = (gint) event->x;
1142 gint ty = (gint) event->y;
1143 gint cx, cy;
1145 gtk_tree_view_get_path_at_pos(view, tx, ty, &path, &column, &cx,
1146 &cy);
1147 if (path == NULL)
1148 return FALSE;
1150 gtk_tree_model_get_iter(model1, &iter, path);
1151 gtk_tree_model_get(model1, &iter, COL_MENU, &menu, -1);
1153 if (event->type == GDK_2BUTTON_PRESS) {
1154 toggle_sym_value(menu);
1155 current = menu;
1156 display_tree_part();
1157 } else {
1158 browsed = menu;
1159 display_tree_part();
1162 gtk_widget_realize(tree2_w);
1163 gtk_tree_view_set_cursor(view, path, NULL, FALSE);
1164 gtk_widget_grab_focus(tree2_w);
1166 return FALSE;
1170 /* Fill a row of strings */
1171 static gchar **fill_row(struct menu *menu)
1173 static gchar *row[COL_NUMBER];
1174 struct symbol *sym = menu->sym;
1175 const char *def;
1176 int stype;
1177 tristate val;
1178 enum prop_type ptype;
1179 int i;
1181 for (i = COL_OPTION; i <= COL_COLOR; i++)
1182 g_free(row[i]);
1183 bzero(row, sizeof(row));
1185 row[COL_OPTION] =
1186 g_strdup_printf("%s %s", menu_get_prompt(menu),
1187 sym && sym_has_value(sym) ? "(NEW)" : "");
1189 if (show_all && !menu_is_visible(menu))
1190 row[COL_COLOR] = g_strdup("DarkGray");
1191 else
1192 row[COL_COLOR] = g_strdup("Black");
1194 ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
1195 switch (ptype) {
1196 case P_MENU:
1197 row[COL_PIXBUF] = (gchar *) xpm_menu;
1198 if (view_mode == SINGLE_VIEW)
1199 row[COL_PIXVIS] = GINT_TO_POINTER(TRUE);
1200 row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
1201 break;
1202 case P_COMMENT:
1203 row[COL_PIXBUF] = (gchar *) xpm_void;
1204 row[COL_PIXVIS] = GINT_TO_POINTER(FALSE);
1205 row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
1206 break;
1207 default:
1208 row[COL_PIXBUF] = (gchar *) xpm_void;
1209 row[COL_PIXVIS] = GINT_TO_POINTER(FALSE);
1210 row[COL_BTNVIS] = GINT_TO_POINTER(TRUE);
1211 break;
1214 if (!sym)
1215 return row;
1216 row[COL_NAME] = g_strdup(sym->name);
1218 sym_calc_value(sym);
1219 sym->flags &= ~SYMBOL_CHANGED;
1221 if (sym_is_choice(sym)) { // parse childs for getting final value
1222 struct menu *child;
1223 struct symbol *def_sym = sym_get_choice_value(sym);
1224 struct menu *def_menu = NULL;
1226 row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
1228 for (child = menu->list; child; child = child->next) {
1229 if (menu_is_visible(child)
1230 && child->sym == def_sym)
1231 def_menu = child;
1234 if (def_menu)
1235 row[COL_VALUE] =
1236 g_strdup(menu_get_prompt(def_menu));
1238 if (sym->flags & SYMBOL_CHOICEVAL)
1239 row[COL_BTNRAD] = GINT_TO_POINTER(TRUE);
1241 stype = sym_get_type(sym);
1242 switch (stype) {
1243 case S_BOOLEAN:
1244 if (GPOINTER_TO_INT(row[COL_PIXVIS]) == FALSE)
1245 row[COL_BTNVIS] = GINT_TO_POINTER(TRUE);
1246 if (sym_is_choice(sym))
1247 break;
1248 case S_TRISTATE:
1249 val = sym_get_tristate_value(sym);
1250 switch (val) {
1251 case no:
1252 row[COL_NO] = g_strdup("N");
1253 row[COL_VALUE] = g_strdup("N");
1254 row[COL_BTNACT] = GINT_TO_POINTER(FALSE);
1255 row[COL_BTNINC] = GINT_TO_POINTER(FALSE);
1256 break;
1257 case mod:
1258 row[COL_MOD] = g_strdup("M");
1259 row[COL_VALUE] = g_strdup("M");
1260 row[COL_BTNINC] = GINT_TO_POINTER(TRUE);
1261 break;
1262 case yes:
1263 row[COL_YES] = g_strdup("Y");
1264 row[COL_VALUE] = g_strdup("Y");
1265 row[COL_BTNACT] = GINT_TO_POINTER(TRUE);
1266 row[COL_BTNINC] = GINT_TO_POINTER(FALSE);
1267 break;
1270 if (val != no && sym_tristate_within_range(sym, no))
1271 row[COL_NO] = g_strdup("_");
1272 if (val != mod && sym_tristate_within_range(sym, mod))
1273 row[COL_MOD] = g_strdup("_");
1274 if (val != yes && sym_tristate_within_range(sym, yes))
1275 row[COL_YES] = g_strdup("_");
1276 break;
1277 case S_INT:
1278 case S_HEX:
1279 case S_STRING:
1280 def = sym_get_string_value(sym);
1281 row[COL_VALUE] = g_strdup(def);
1282 row[COL_EDIT] = GINT_TO_POINTER(TRUE);
1283 row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
1284 break;
1287 return row;
1291 /* Set the node content with a row of strings */
1292 static void set_node(GtkTreeIter * node, struct menu *menu, gchar ** row)
1294 GdkColor color;
1295 gboolean success;
1296 GdkPixbuf *pix;
1298 pix = gdk_pixbuf_new_from_xpm_data((const char **)
1299 row[COL_PIXBUF]);
1301 gdk_color_parse(row[COL_COLOR], &color);
1302 gdk_colormap_alloc_colors(gdk_colormap_get_system(), &color, 1,
1303 FALSE, FALSE, &success);
1305 gtk_tree_store_set(tree, node,
1306 COL_OPTION, row[COL_OPTION],
1307 COL_NAME, row[COL_NAME],
1308 COL_NO, row[COL_NO],
1309 COL_MOD, row[COL_MOD],
1310 COL_YES, row[COL_YES],
1311 COL_VALUE, row[COL_VALUE],
1312 COL_MENU, (gpointer) menu,
1313 COL_COLOR, &color,
1314 COL_EDIT, GPOINTER_TO_INT(row[COL_EDIT]),
1315 COL_PIXBUF, pix,
1316 COL_PIXVIS, GPOINTER_TO_INT(row[COL_PIXVIS]),
1317 COL_BTNVIS, GPOINTER_TO_INT(row[COL_BTNVIS]),
1318 COL_BTNACT, GPOINTER_TO_INT(row[COL_BTNACT]),
1319 COL_BTNINC, GPOINTER_TO_INT(row[COL_BTNINC]),
1320 COL_BTNRAD, GPOINTER_TO_INT(row[COL_BTNRAD]),
1321 -1);
1323 g_object_unref(pix);
1327 /* Add a node to the tree */
1328 static void place_node(struct menu *menu, char **row)
1330 GtkTreeIter *parent = parents[indent - 1];
1331 GtkTreeIter *node = parents[indent];
1333 gtk_tree_store_append(tree, node, parent);
1334 set_node(node, menu, row);
1338 /* Find a node in the GTK+ tree */
1339 static GtkTreeIter found;
1341 /*
1342 * Find a menu in the GtkTree starting at parent.
1343 */
1344 GtkTreeIter *gtktree_iter_find_node(GtkTreeIter * parent,
1345 struct menu *tofind)
1347 GtkTreeIter iter;
1348 GtkTreeIter *child = &iter;
1349 gboolean valid;
1350 GtkTreeIter *ret;
1352 valid = gtk_tree_model_iter_children(model2, child, parent);
1353 while (valid) {
1354 struct menu *menu;
1356 gtk_tree_model_get(model2, child, 6, &menu, -1);
1358 if (menu == tofind) {
1359 memcpy(&found, child, sizeof(GtkTreeIter));
1360 return &found;
1363 ret = gtktree_iter_find_node(child, tofind);
1364 if (ret)
1365 return ret;
1367 valid = gtk_tree_model_iter_next(model2, child);
1370 return NULL;
1374 /*
1375 * Update the tree by adding/removing entries
1376 * Does not change other nodes
1377 */
1378 static void update_tree(struct menu *src, GtkTreeIter * dst)
1380 struct menu *child1;
1381 GtkTreeIter iter, tmp;
1382 GtkTreeIter *child2 = &iter;
1383 gboolean valid;
1384 GtkTreeIter *sibling;
1385 struct symbol *sym;
1386 struct property *prop;
1387 struct menu *menu1, *menu2;
1389 if (src == &rootmenu)
1390 indent = 1;
1392 valid = gtk_tree_model_iter_children(model2, child2, dst);
1393 for (child1 = src->list; child1; child1 = child1->next) {
1395 prop = child1->prompt;
1396 sym = child1->sym;
1398 reparse:
1399 menu1 = child1;
1400 if (valid)
1401 gtk_tree_model_get(model2, child2, COL_MENU,
1402 &menu2, -1);
1403 else
1404 menu2 = NULL; // force adding of a first child
1406 #ifdef DEBUG
1407 printf("%*c%s | %s\n", indent, ' ',
1408 menu1 ? menu_get_prompt(menu1) : "nil",
1409 menu2 ? menu_get_prompt(menu2) : "nil");
1410 #endif
1412 if (!menu_is_visible(child1) && !show_all) { // remove node
1413 if (gtktree_iter_find_node(dst, menu1) != NULL) {
1414 memcpy(&tmp, child2, sizeof(GtkTreeIter));
1415 valid = gtk_tree_model_iter_next(model2,
1416 child2);
1417 gtk_tree_store_remove(tree2, &tmp);
1418 if (!valid)
1419 return; // next parent
1420 else
1421 goto reparse; // next child
1422 } else
1423 continue;
1426 if (menu1 != menu2) {
1427 if (gtktree_iter_find_node(dst, menu1) == NULL) { // add node
1428 if (!valid && !menu2)
1429 sibling = NULL;
1430 else
1431 sibling = child2;
1432 gtk_tree_store_insert_before(tree2,
1433 child2,
1434 dst, sibling);
1435 set_node(child2, menu1, fill_row(menu1));
1436 if (menu2 == NULL)
1437 valid = TRUE;
1438 } else { // remove node
1439 memcpy(&tmp, child2, sizeof(GtkTreeIter));
1440 valid = gtk_tree_model_iter_next(model2,
1441 child2);
1442 gtk_tree_store_remove(tree2, &tmp);
1443 if (!valid)
1444 return; // next parent
1445 else
1446 goto reparse; // next child
1448 } else if (sym && (sym->flags & SYMBOL_CHANGED)) {
1449 set_node(child2, menu1, fill_row(menu1));
1452 indent++;
1453 update_tree(child1, child2);
1454 indent--;
1456 valid = gtk_tree_model_iter_next(model2, child2);
1461 /* Display the whole tree (single/split/full view) */
1462 static void display_tree(struct menu *menu)
1464 struct symbol *sym;
1465 struct property *prop;
1466 struct menu *child;
1467 enum prop_type ptype;
1469 if (menu == &rootmenu) {
1470 indent = 1;
1471 current = &rootmenu;
1474 for (child = menu->list; child; child = child->next) {
1475 prop = child->prompt;
1476 sym = child->sym;
1477 ptype = prop ? prop->type : P_UNKNOWN;
1479 if (sym)
1480 sym->flags &= ~SYMBOL_CHANGED;
1482 if ((view_mode == SPLIT_VIEW)
1483 && !(child->flags & MENU_ROOT) && (tree == tree1))
1484 continue;
1486 if ((view_mode == SPLIT_VIEW) && (child->flags & MENU_ROOT)
1487 && (tree == tree2))
1488 continue;
1490 if (menu_is_visible(child) || show_all)
1491 place_node(child, fill_row(child));
1492 #ifdef DEBUG
1493 printf("%*c%s: ", indent, ' ', menu_get_prompt(child));
1494 printf("%s", child->flags & MENU_ROOT ? "rootmenu | " : "");
1495 dbg_print_ptype(ptype);
1496 printf(" | ");
1497 if (sym) {
1498 dbg_print_stype(sym->type);
1499 printf(" | ");
1500 dbg_print_flags(sym->flags);
1501 printf("\n");
1502 } else
1503 printf("\n");
1504 #endif
1505 if ((view_mode != FULL_VIEW) && (ptype == P_MENU)
1506 && (tree == tree2))
1507 continue;
1508 /*
1509 if (((menu != &rootmenu) && !(menu->flags & MENU_ROOT))
1510 || (view_mode == FULL_VIEW)
1511 || (view_mode == SPLIT_VIEW))*/
1512 if (((view_mode == SINGLE_VIEW) && (menu->flags & MENU_ROOT))
1513 || (view_mode == FULL_VIEW)
1514 || (view_mode == SPLIT_VIEW)) {
1515 indent++;
1516 display_tree(child);
1517 indent--;
1522 /* Display a part of the tree starting at current node (single/split view) */
1523 static void display_tree_part(void)
1525 if (tree2)
1526 gtk_tree_store_clear(tree2);
1527 if (view_mode == SINGLE_VIEW)
1528 display_tree(current);
1529 else if (view_mode == SPLIT_VIEW)
1530 display_tree(browsed);
1531 gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w));
1534 /* Display the list in the left frame (split view) */
1535 static void display_list(void)
1537 if (tree1)
1538 gtk_tree_store_clear(tree1);
1540 tree = tree1;
1541 display_tree(&rootmenu);
1542 gtk_tree_view_expand_all(GTK_TREE_VIEW(tree1_w));
1543 tree = tree2;
1546 void fixup_rootmenu(struct menu *menu)
1548 struct menu *child;
1549 static int menu_cnt = 0;
1551 menu->flags |= MENU_ROOT;
1552 for (child = menu->list; child; child = child->next) {
1553 if (child->prompt && child->prompt->type == P_MENU) {
1554 menu_cnt++;
1555 fixup_rootmenu(child);
1556 menu_cnt--;
1557 } else if (!menu_cnt)
1558 fixup_rootmenu(child);
1563 /* Main */
1564 int main(int ac, char *av[])
1566 const char *name;
1567 char *env;
1568 gchar *glade_file;
1570 #ifndef LKC_DIRECT_LINK
1571 kconfig_load();
1572 #endif
1574 bindtextdomain(PACKAGE, LOCALEDIR);
1575 bind_textdomain_codeset(PACKAGE, "UTF-8");
1576 textdomain(PACKAGE);
1578 /* GTK stuffs */
1579 gtk_set_locale();
1580 gtk_init(&ac, &av);
1581 glade_init();
1583 //add_pixmap_directory (PACKAGE_DATA_DIR "/" PACKAGE "/pixmaps");
1584 //add_pixmap_directory (PACKAGE_SOURCE_DIR "/pixmaps");
1586 /* Determine GUI path */
1587 env = getenv(SRCTREE);
1588 if (env)
1589 glade_file = g_strconcat(env, "/scripts/kconfig/gconf.glade", NULL);
1590 else if (av[0][0] == '/')
1591 glade_file = g_strconcat(av[0], ".glade", NULL);
1592 else
1593 glade_file = g_strconcat(g_get_current_dir(), "/", av[0], ".glade", NULL);
1595 /* Load the interface and connect signals */
1596 init_main_window(glade_file);
1597 init_tree_model();
1598 init_left_tree();
1599 init_right_tree();
1601 /* Conf stuffs */
1602 if (ac > 1 && av[1][0] == '-') {
1603 switch (av[1][1]) {
1604 case 'a':
1605 //showAll = 1;
1606 break;
1607 case 'h':
1608 case '?':
1609 printf("%s <config>\n", av[0]);
1610 exit(0);
1612 name = av[2];
1613 } else
1614 name = av[1];
1616 conf_parse(name);
1617 fixup_rootmenu(&rootmenu);
1618 conf_read(NULL);
1620 switch (view_mode) {
1621 case SINGLE_VIEW:
1622 display_tree_part();
1623 break;
1624 case SPLIT_VIEW:
1625 display_list();
1626 break;
1627 case FULL_VIEW:
1628 display_tree(&rootmenu);
1629 break;
1632 gtk_main();
1634 return 0;