1 /* Hey EMACS -*- linux-c -*- */
4 * Copyright (C) 2002-2003 Romain Lievin <roms@tilp.info>
5 * Released under the terms of the GNU GPL v2.0.
17 #include <glade/glade.h>
20 #include <gdk/gdkkeysyms.h>
29 int kconfig_warnings
= 0;
32 SINGLE_VIEW
, SPLIT_VIEW
, FULL_VIEW
36 OPT_NORMAL
, OPT_ALL
, OPT_PROMPT
39 static gint view_mode
= FULL_VIEW
;
40 static gboolean show_name
= TRUE
;
41 static gboolean show_range
= TRUE
;
42 static gboolean show_value
= TRUE
;
43 static gboolean resizeable
= FALSE
;
44 static int opt_mode
= OPT_NORMAL
;
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
;
53 GtkWidget
*save_btn
= NULL
;
54 GtkWidget
*save_menu_item
= NULL
;
56 GtkTextTag
*tag1
, *tag2
;
59 GtkTreeStore
*tree1
, *tree2
, *tree
;
60 GtkTreeModel
*model1
, *model2
;
61 static GtkTreeIter
*parents
[256];
64 static struct menu
*current
; // current node for SINGLE view
65 static struct menu
*browsed
; // browsed node for SPLIT view
68 COL_OPTION
, COL_NAME
, COL_NO
, COL_MOD
, COL_YES
, COL_VALUE
,
69 COL_MENU
, COL_COLOR
, COL_EDIT
, COL_PIXBUF
,
70 COL_PIXVIS
, COL_BTNVIS
, COL_BTNACT
, COL_BTNINC
, COL_BTNRAD
,
74 static void display_list(void);
75 static void display_tree(struct menu
*menu
);
76 static void display_tree_part(void);
77 static void update_tree(struct menu
*src
, GtkTreeIter
* dst
);
78 static void set_node(GtkTreeIter
* node
, struct menu
*menu
, gchar
** row
);
79 static gchar
**fill_row(struct menu
*menu
);
80 static void conf_changed(void);
82 /* Helping/Debugging Functions */
84 const char *dbg_sym_flags(int val
)
90 if (val
& SYMBOL_CONST
)
91 strcat(buf
, "const/");
92 if (val
& SYMBOL_CHECK
)
93 strcat(buf
, "check/");
94 if (val
& SYMBOL_CHOICE
)
95 strcat(buf
, "choice/");
96 if (val
& SYMBOL_CHOICEVAL
)
97 strcat(buf
, "choiceval/");
98 if (val
& SYMBOL_VALID
)
99 strcat(buf
, "valid/");
100 if (val
& SYMBOL_OPTIONAL
)
101 strcat(buf
, "optional/");
102 if (val
& SYMBOL_WRITE
)
103 strcat(buf
, "write/");
104 if (val
& SYMBOL_CHANGED
)
105 strcat(buf
, "changed/");
106 if (val
& SYMBOL_AUTO
)
107 strcat(buf
, "auto/");
109 buf
[strlen(buf
) - 1] = '\0';
114 void replace_button_icon(GladeXML
* xml
, GdkDrawable
* window
,
115 GtkStyle
* style
, gchar
* btn_name
, gchar
** xpm
)
119 GtkToolButton
*button
;
122 pixmap
= gdk_pixmap_create_from_xpm_d(window
, &mask
,
123 &style
->bg
[GTK_STATE_NORMAL
],
126 button
= GTK_TOOL_BUTTON(glade_xml_get_widget(xml
, btn_name
));
127 image
= gtk_image_new_from_pixmap(pixmap
, mask
);
128 gtk_widget_show(image
);
129 gtk_tool_button_set_icon_widget(button
, image
);
132 /* Main Window Initialization */
133 void init_main_window(const gchar
* glade_file
)
137 GtkTextBuffer
*txtbuf
;
140 xml
= glade_xml_new(glade_file
, "window1", NULL
);
142 g_error(_("GUI loading failed !\n"));
143 glade_xml_signal_autoconnect(xml
);
145 main_wnd
= glade_xml_get_widget(xml
, "window1");
146 hpaned
= glade_xml_get_widget(xml
, "hpaned1");
147 vpaned
= glade_xml_get_widget(xml
, "vpaned1");
148 tree1_w
= glade_xml_get_widget(xml
, "treeview1");
149 tree2_w
= glade_xml_get_widget(xml
, "treeview2");
150 text_w
= glade_xml_get_widget(xml
, "textview3");
152 back_btn
= glade_xml_get_widget(xml
, "button1");
153 gtk_widget_set_sensitive(back_btn
, FALSE
);
155 widget
= glade_xml_get_widget(xml
, "show_name1");
156 gtk_check_menu_item_set_active((GtkCheckMenuItem
*) widget
,
159 widget
= glade_xml_get_widget(xml
, "show_range1");
160 gtk_check_menu_item_set_active((GtkCheckMenuItem
*) widget
,
163 widget
= glade_xml_get_widget(xml
, "show_data1");
164 gtk_check_menu_item_set_active((GtkCheckMenuItem
*) widget
,
167 save_btn
= glade_xml_get_widget(xml
, "button3");
168 save_menu_item
= glade_xml_get_widget(xml
, "save1");
169 conf_set_changed_callback(conf_changed
);
171 style
= gtk_widget_get_style(main_wnd
);
172 widget
= glade_xml_get_widget(xml
, "toolbar1");
174 #if 0 /* Use stock Gtk icons instead */
175 replace_button_icon(xml
, main_wnd
->window
, style
,
176 "button1", (gchar
**) xpm_back
);
177 replace_button_icon(xml
, main_wnd
->window
, style
,
178 "button2", (gchar
**) xpm_load
);
179 replace_button_icon(xml
, main_wnd
->window
, style
,
180 "button3", (gchar
**) xpm_save
);
182 replace_button_icon(xml
, main_wnd
->window
, style
,
183 "button4", (gchar
**) xpm_single_view
);
184 replace_button_icon(xml
, main_wnd
->window
, style
,
185 "button5", (gchar
**) xpm_split_view
);
186 replace_button_icon(xml
, main_wnd
->window
, style
,
187 "button6", (gchar
**) xpm_tree_view
);
192 widget
= glade_xml_get_widget(xml
, "button4");
193 g_signal_emit_by_name(widget
, "clicked");
196 widget
= glade_xml_get_widget(xml
, "button5");
197 g_signal_emit_by_name(widget
, "clicked");
200 widget
= glade_xml_get_widget(xml
, "button6");
201 g_signal_emit_by_name(widget
, "clicked");
205 txtbuf
= gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w
));
206 tag1
= gtk_text_buffer_create_tag(txtbuf
, "mytag1",
208 "weight", PANGO_WEIGHT_BOLD
,
210 tag2
= gtk_text_buffer_create_tag(txtbuf
, "mytag2",
211 /*"style", PANGO_STYLE_OBLIQUE, */
214 gtk_window_set_title(GTK_WINDOW(main_wnd
), rootmenu
.prompt
->text
);
216 gtk_widget_show(main_wnd
);
219 void init_tree_model(void)
223 tree
= tree2
= gtk_tree_store_new(COL_NUMBER
,
224 G_TYPE_STRING
, G_TYPE_STRING
,
225 G_TYPE_STRING
, G_TYPE_STRING
,
226 G_TYPE_STRING
, G_TYPE_STRING
,
227 G_TYPE_POINTER
, GDK_TYPE_COLOR
,
228 G_TYPE_BOOLEAN
, GDK_TYPE_PIXBUF
,
229 G_TYPE_BOOLEAN
, G_TYPE_BOOLEAN
,
230 G_TYPE_BOOLEAN
, G_TYPE_BOOLEAN
,
232 model2
= GTK_TREE_MODEL(tree2
);
234 for (parents
[0] = NULL
, i
= 1; i
< 256; i
++)
235 parents
[i
] = (GtkTreeIter
*) g_malloc(sizeof(GtkTreeIter
));
237 tree1
= gtk_tree_store_new(COL_NUMBER
,
238 G_TYPE_STRING
, G_TYPE_STRING
,
239 G_TYPE_STRING
, G_TYPE_STRING
,
240 G_TYPE_STRING
, G_TYPE_STRING
,
241 G_TYPE_POINTER
, GDK_TYPE_COLOR
,
242 G_TYPE_BOOLEAN
, GDK_TYPE_PIXBUF
,
243 G_TYPE_BOOLEAN
, G_TYPE_BOOLEAN
,
244 G_TYPE_BOOLEAN
, G_TYPE_BOOLEAN
,
246 model1
= GTK_TREE_MODEL(tree1
);
249 void init_left_tree(void)
251 GtkTreeView
*view
= GTK_TREE_VIEW(tree1_w
);
252 GtkCellRenderer
*renderer
;
253 GtkTreeSelection
*sel
;
254 GtkTreeViewColumn
*column
;
256 gtk_tree_view_set_model(view
, model1
);
257 gtk_tree_view_set_headers_visible(view
, TRUE
);
258 gtk_tree_view_set_rules_hint(view
, TRUE
);
260 column
= gtk_tree_view_column_new();
261 gtk_tree_view_append_column(view
, column
);
262 gtk_tree_view_column_set_title(column
, _("Options"));
264 renderer
= gtk_cell_renderer_toggle_new();
265 gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column
),
267 gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column
),
269 "active", COL_BTNACT
,
270 "inconsistent", COL_BTNINC
,
271 "visible", COL_BTNVIS
,
272 "radio", COL_BTNRAD
, NULL
);
273 renderer
= gtk_cell_renderer_text_new();
274 gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column
),
276 gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column
),
282 sel
= gtk_tree_view_get_selection(view
);
283 gtk_tree_selection_set_mode(sel
, GTK_SELECTION_SINGLE
);
284 gtk_widget_realize(tree1_w
);
287 static void renderer_edited(GtkCellRendererText
* cell
,
288 const gchar
* path_string
,
289 const gchar
* new_text
, gpointer user_data
);
291 void init_right_tree(void)
293 GtkTreeView
*view
= GTK_TREE_VIEW(tree2_w
);
294 GtkCellRenderer
*renderer
;
295 GtkTreeSelection
*sel
;
296 GtkTreeViewColumn
*column
;
299 gtk_tree_view_set_model(view
, model2
);
300 gtk_tree_view_set_headers_visible(view
, TRUE
);
301 gtk_tree_view_set_rules_hint(view
, TRUE
);
303 column
= gtk_tree_view_column_new();
304 gtk_tree_view_append_column(view
, column
);
305 gtk_tree_view_column_set_title(column
, _("Options"));
307 renderer
= gtk_cell_renderer_pixbuf_new();
308 gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column
),
310 gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column
),
312 "pixbuf", COL_PIXBUF
,
313 "visible", COL_PIXVIS
, NULL
);
314 renderer
= gtk_cell_renderer_toggle_new();
315 gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column
),
317 gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column
),
319 "active", COL_BTNACT
,
320 "inconsistent", COL_BTNINC
,
321 "visible", COL_BTNVIS
,
322 "radio", COL_BTNRAD
, NULL
);
323 renderer
= gtk_cell_renderer_text_new();
324 gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column
),
326 gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column
),
332 renderer
= gtk_cell_renderer_text_new();
333 gtk_tree_view_insert_column_with_attributes(view
, -1,
338 renderer
= gtk_cell_renderer_text_new();
339 gtk_tree_view_insert_column_with_attributes(view
, -1,
344 renderer
= gtk_cell_renderer_text_new();
345 gtk_tree_view_insert_column_with_attributes(view
, -1,
350 renderer
= gtk_cell_renderer_text_new();
351 gtk_tree_view_insert_column_with_attributes(view
, -1,
356 renderer
= gtk_cell_renderer_text_new();
357 gtk_tree_view_insert_column_with_attributes(view
, -1,
358 _("Value"), renderer
,
364 g_signal_connect(G_OBJECT(renderer
), "edited",
365 G_CALLBACK(renderer_edited
), NULL
);
367 column
= gtk_tree_view_get_column(view
, COL_NAME
);
368 gtk_tree_view_column_set_visible(column
, show_name
);
369 column
= gtk_tree_view_get_column(view
, COL_NO
);
370 gtk_tree_view_column_set_visible(column
, show_range
);
371 column
= gtk_tree_view_get_column(view
, COL_MOD
);
372 gtk_tree_view_column_set_visible(column
, show_range
);
373 column
= gtk_tree_view_get_column(view
, COL_YES
);
374 gtk_tree_view_column_set_visible(column
, show_range
);
375 column
= gtk_tree_view_get_column(view
, COL_VALUE
);
376 gtk_tree_view_column_set_visible(column
, show_value
);
379 for (i
= 0; i
< COL_VALUE
; i
++) {
380 column
= gtk_tree_view_get_column(view
, i
);
381 gtk_tree_view_column_set_resizable(column
, TRUE
);
385 sel
= gtk_tree_view_get_selection(view
);
386 gtk_tree_selection_set_mode(sel
, GTK_SELECTION_SINGLE
);
390 /* Utility Functions */
393 static void text_insert_help(struct menu
*menu
)
395 GtkTextBuffer
*buffer
;
396 GtkTextIter start
, end
;
397 const char *prompt
= _(menu_get_prompt(menu
));
398 struct gstr help
= str_new();
400 menu_get_ext_help(menu
, &help
);
402 buffer
= gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w
));
403 gtk_text_buffer_get_bounds(buffer
, &start
, &end
);
404 gtk_text_buffer_delete(buffer
, &start
, &end
);
405 gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_w
), 15);
407 gtk_text_buffer_get_end_iter(buffer
, &end
);
408 gtk_text_buffer_insert_with_tags(buffer
, &end
, prompt
, -1, tag1
,
410 gtk_text_buffer_insert_at_cursor(buffer
, "\n\n", 2);
411 gtk_text_buffer_get_end_iter(buffer
, &end
);
412 gtk_text_buffer_insert_with_tags(buffer
, &end
, str_get(&help
), -1, tag2
,
418 static void text_insert_msg(const char *title
, const char *message
)
420 GtkTextBuffer
*buffer
;
421 GtkTextIter start
, end
;
422 const char *msg
= message
;
424 buffer
= gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w
));
425 gtk_text_buffer_get_bounds(buffer
, &start
, &end
);
426 gtk_text_buffer_delete(buffer
, &start
, &end
);
427 gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_w
), 15);
429 gtk_text_buffer_get_end_iter(buffer
, &end
);
430 gtk_text_buffer_insert_with_tags(buffer
, &end
, title
, -1, tag1
,
432 gtk_text_buffer_insert_at_cursor(buffer
, "\n\n", 2);
433 gtk_text_buffer_get_end_iter(buffer
, &end
);
434 gtk_text_buffer_insert_with_tags(buffer
, &end
, msg
, -1, tag2
,
439 /* Main Windows Callbacks */
441 void on_save_activate(GtkMenuItem
* menuitem
, gpointer user_data
);
442 gboolean
on_window1_delete_event(GtkWidget
* widget
, GdkEvent
* event
,
445 GtkWidget
*dialog
, *label
;
448 if (!conf_get_changed())
451 dialog
= gtk_dialog_new_with_buttons(_("Warning !"),
452 GTK_WINDOW(main_wnd
),
455 GTK_DIALOG_DESTROY_WITH_PARENT
),
461 GTK_RESPONSE_CANCEL
, NULL
);
462 gtk_dialog_set_default_response(GTK_DIALOG(dialog
),
463 GTK_RESPONSE_CANCEL
);
465 label
= gtk_label_new(_("\nSave configuration ?\n"));
466 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog
)->vbox
), label
);
467 gtk_widget_show(label
);
469 result
= gtk_dialog_run(GTK_DIALOG(dialog
));
471 case GTK_RESPONSE_YES
:
472 on_save_activate(NULL
, NULL
);
474 case GTK_RESPONSE_NO
:
476 case GTK_RESPONSE_CANCEL
:
477 case GTK_RESPONSE_DELETE_EVENT
:
479 gtk_widget_destroy(dialog
);
487 void on_window1_destroy(GtkObject
* object
, gpointer user_data
)
494 on_window1_size_request(GtkWidget
* widget
,
495 GtkRequisition
* requisition
, gpointer user_data
)
500 if (widget
->window
== NULL
)
501 gtk_window_get_default_size(GTK_WINDOW(main_wnd
), &w
, &h
);
503 gdk_window_get_size(widget
->window
, &w
, &h
);
509 gtk_paned_set_position(GTK_PANED(vpaned
), 2 * h
/ 3);
513 /* Menu & Toolbar Callbacks */
517 load_filename(GtkFileSelection
* file_selector
, gpointer user_data
)
521 fn
= gtk_file_selection_get_filename(GTK_FILE_SELECTION
525 text_insert_msg(_("Error"), _("Unable to load configuration !"));
527 display_tree(&rootmenu
);
530 void on_load1_activate(GtkMenuItem
* menuitem
, gpointer user_data
)
534 fs
= gtk_file_selection_new(_("Load file..."));
535 g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs
)->ok_button
),
537 G_CALLBACK(load_filename
), (gpointer
) fs
);
538 g_signal_connect_swapped(GTK_OBJECT
539 (GTK_FILE_SELECTION(fs
)->ok_button
),
540 "clicked", G_CALLBACK(gtk_widget_destroy
),
542 g_signal_connect_swapped(GTK_OBJECT
543 (GTK_FILE_SELECTION(fs
)->cancel_button
),
544 "clicked", G_CALLBACK(gtk_widget_destroy
),
550 void on_save_activate(GtkMenuItem
* menuitem
, gpointer user_data
)
552 if (conf_write(NULL
))
553 text_insert_msg(_("Error"), _("Unable to save configuration !"));
558 store_filename(GtkFileSelection
* file_selector
, gpointer user_data
)
562 fn
= gtk_file_selection_get_filename(GTK_FILE_SELECTION
566 text_insert_msg(_("Error"), _("Unable to save configuration !"));
568 gtk_widget_destroy(GTK_WIDGET(user_data
));
571 void on_save_as1_activate(GtkMenuItem
* menuitem
, gpointer user_data
)
575 fs
= gtk_file_selection_new(_("Save file as..."));
576 g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs
)->ok_button
),
578 G_CALLBACK(store_filename
), (gpointer
) fs
);
579 g_signal_connect_swapped(GTK_OBJECT
580 (GTK_FILE_SELECTION(fs
)->ok_button
),
581 "clicked", G_CALLBACK(gtk_widget_destroy
),
583 g_signal_connect_swapped(GTK_OBJECT
584 (GTK_FILE_SELECTION(fs
)->cancel_button
),
585 "clicked", G_CALLBACK(gtk_widget_destroy
),
591 void on_quit1_activate(GtkMenuItem
* menuitem
, gpointer user_data
)
593 if (!on_window1_delete_event(NULL
, NULL
, NULL
))
594 gtk_widget_destroy(GTK_WIDGET(main_wnd
));
598 void on_show_name1_activate(GtkMenuItem
* menuitem
, gpointer user_data
)
600 GtkTreeViewColumn
*col
;
602 show_name
= GTK_CHECK_MENU_ITEM(menuitem
)->active
;
603 col
= gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w
), COL_NAME
);
605 gtk_tree_view_column_set_visible(col
, show_name
);
609 void on_show_range1_activate(GtkMenuItem
* menuitem
, gpointer user_data
)
611 GtkTreeViewColumn
*col
;
613 show_range
= GTK_CHECK_MENU_ITEM(menuitem
)->active
;
614 col
= gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w
), COL_NO
);
616 gtk_tree_view_column_set_visible(col
, show_range
);
617 col
= gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w
), COL_MOD
);
619 gtk_tree_view_column_set_visible(col
, show_range
);
620 col
= gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w
), COL_YES
);
622 gtk_tree_view_column_set_visible(col
, show_range
);
627 void on_show_data1_activate(GtkMenuItem
* menuitem
, gpointer user_data
)
629 GtkTreeViewColumn
*col
;
631 show_value
= GTK_CHECK_MENU_ITEM(menuitem
)->active
;
632 col
= gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w
), COL_VALUE
);
634 gtk_tree_view_column_set_visible(col
, show_value
);
639 on_set_option_mode1_activate(GtkMenuItem
*menuitem
, gpointer user_data
)
641 opt_mode
= OPT_NORMAL
;
642 gtk_tree_store_clear(tree2
);
643 display_tree(&rootmenu
); /* instead of update_tree to speed-up */
648 on_set_option_mode2_activate(GtkMenuItem
*menuitem
, gpointer user_data
)
651 gtk_tree_store_clear(tree2
);
652 display_tree(&rootmenu
); /* instead of update_tree to speed-up */
657 on_set_option_mode3_activate(GtkMenuItem
*menuitem
, gpointer user_data
)
659 opt_mode
= OPT_PROMPT
;
660 gtk_tree_store_clear(tree2
);
661 display_tree(&rootmenu
); /* instead of update_tree to speed-up */
665 void on_introduction1_activate(GtkMenuItem
* menuitem
, gpointer user_data
)
668 const gchar
*intro_text
= _(
669 "Welcome to gkc, the GTK+ graphical configuration tool\n"
670 "For each option, a blank box indicates the feature is disabled, a\n"
671 "check indicates it is enabled, and a dot indicates that it is to\n"
672 "be compiled as a module. Clicking on the box will cycle through the three states.\n"
674 "If you do not see an option (e.g., a device driver) that you\n"
675 "believe should be present, try turning on Show All Options\n"
676 "under the Options menu.\n"
677 "Although there is no cross reference yet to help you figure out\n"
678 "what other options must be enabled to support the option you\n"
679 "are interested in, you can still view the help of a grayed-out\n"
682 "Toggling Show Debug Info under the Options menu will show \n"
683 "the dependencies, which you can then match by examining other options.");
685 dialog
= gtk_message_dialog_new(GTK_WINDOW(main_wnd
),
686 GTK_DIALOG_DESTROY_WITH_PARENT
,
688 GTK_BUTTONS_CLOSE
, "%s", intro_text
);
689 g_signal_connect_swapped(GTK_OBJECT(dialog
), "response",
690 G_CALLBACK(gtk_widget_destroy
),
692 gtk_widget_show_all(dialog
);
696 void on_about1_activate(GtkMenuItem
* menuitem
, gpointer user_data
)
699 const gchar
*about_text
=
700 _("gkc is copyright (c) 2002 Romain Lievin <roms@lpg.ticalc.org>.\n"
701 "Based on the source code from Roman Zippel.\n");
703 dialog
= gtk_message_dialog_new(GTK_WINDOW(main_wnd
),
704 GTK_DIALOG_DESTROY_WITH_PARENT
,
706 GTK_BUTTONS_CLOSE
, "%s", about_text
);
707 g_signal_connect_swapped(GTK_OBJECT(dialog
), "response",
708 G_CALLBACK(gtk_widget_destroy
),
710 gtk_widget_show_all(dialog
);
714 void on_license1_activate(GtkMenuItem
* menuitem
, gpointer user_data
)
717 const gchar
*license_text
=
718 _("gkc is released under the terms of the GNU GPL v2.\n"
719 "For more information, please see the source code or\n"
720 "visit http://www.fsf.org/licenses/licenses.html\n");
722 dialog
= gtk_message_dialog_new(GTK_WINDOW(main_wnd
),
723 GTK_DIALOG_DESTROY_WITH_PARENT
,
725 GTK_BUTTONS_CLOSE
, "%s", license_text
);
726 g_signal_connect_swapped(GTK_OBJECT(dialog
), "response",
727 G_CALLBACK(gtk_widget_destroy
),
729 gtk_widget_show_all(dialog
);
733 void on_back_clicked(GtkButton
* button
, gpointer user_data
)
735 enum prop_type ptype
;
737 current
= current
->parent
;
738 ptype
= current
->prompt
? current
->prompt
->type
: P_UNKNOWN
;
740 current
= current
->parent
;
743 if (current
== &rootmenu
)
744 gtk_widget_set_sensitive(back_btn
, FALSE
);
748 void on_load_clicked(GtkButton
* button
, gpointer user_data
)
750 on_load1_activate(NULL
, user_data
);
754 void on_single_clicked(GtkButton
* button
, gpointer user_data
)
756 view_mode
= SINGLE_VIEW
;
757 gtk_widget_hide(tree1_w
);
763 void on_split_clicked(GtkButton
* button
, gpointer user_data
)
766 view_mode
= SPLIT_VIEW
;
767 gtk_widget_show(tree1_w
);
768 gtk_window_get_default_size(GTK_WINDOW(main_wnd
), &w
, &h
);
769 gtk_paned_set_position(GTK_PANED(hpaned
), w
/ 2);
771 gtk_tree_store_clear(tree2
);
774 /* Disable back btn, like in full mode. */
775 gtk_widget_set_sensitive(back_btn
, FALSE
);
779 void on_full_clicked(GtkButton
* button
, gpointer user_data
)
781 view_mode
= FULL_VIEW
;
782 gtk_widget_hide(tree1_w
);
784 gtk_tree_store_clear(tree2
);
785 display_tree(&rootmenu
);
786 gtk_widget_set_sensitive(back_btn
, FALSE
);
790 void on_collapse_clicked(GtkButton
* button
, gpointer user_data
)
792 gtk_tree_view_collapse_all(GTK_TREE_VIEW(tree2_w
));
796 void on_expand_clicked(GtkButton
* button
, gpointer user_data
)
798 gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w
));
802 /* CTree Callbacks */
804 /* Change hex/int/string value in the cell */
805 static void renderer_edited(GtkCellRendererText
* cell
,
806 const gchar
* path_string
,
807 const gchar
* new_text
, gpointer user_data
)
809 GtkTreePath
*path
= gtk_tree_path_new_from_string(path_string
);
811 const char *old_def
, *new_def
;
815 if (!gtk_tree_model_get_iter(model2
, &iter
, path
))
818 gtk_tree_model_get(model2
, &iter
, COL_MENU
, &menu
, -1);
821 gtk_tree_model_get(model2
, &iter
, COL_VALUE
, &old_def
, -1);
824 sym_set_string_value(sym
, new_def
);
826 update_tree(&rootmenu
, NULL
);
828 gtk_tree_path_free(path
);
831 /* Change the value of a symbol and update the tree */
832 static void change_sym_value(struct menu
*menu
, gint col
)
834 struct symbol
*sym
= menu
->sym
;
842 else if (col
== COL_MOD
)
844 else if (col
== COL_YES
)
849 switch (sym_get_type(sym
)) {
852 if (!sym_tristate_within_range(sym
, newval
))
854 sym_set_tristate_value(sym
, newval
);
855 if (view_mode
== FULL_VIEW
)
856 update_tree(&rootmenu
, NULL
);
857 else if (view_mode
== SPLIT_VIEW
) {
858 update_tree(browsed
, NULL
);
861 else if (view_mode
== SINGLE_VIEW
)
862 display_tree_part(); //fixme: keep exp/coll
872 static void toggle_sym_value(struct menu
*menu
)
877 sym_toggle_tristate_value(menu
->sym
);
878 if (view_mode
== FULL_VIEW
)
879 update_tree(&rootmenu
, NULL
);
880 else if (view_mode
== SPLIT_VIEW
) {
881 update_tree(browsed
, NULL
);
884 else if (view_mode
== SINGLE_VIEW
)
885 display_tree_part(); //fixme: keep exp/coll
888 static gint
column2index(GtkTreeViewColumn
* column
)
892 for (i
= 0; i
< COL_NUMBER
; i
++) {
893 GtkTreeViewColumn
*col
;
895 col
= gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w
), i
);
904 /* User click: update choice (full) or goes down (single) */
906 on_treeview2_button_press_event(GtkWidget
* widget
,
907 GdkEventButton
* event
, gpointer user_data
)
909 GtkTreeView
*view
= GTK_TREE_VIEW(widget
);
911 GtkTreeViewColumn
*column
;
916 #if GTK_CHECK_VERSION(2,1,4) // bug in ctree with earlier version of GTK
917 gint tx
= (gint
) event
->x
;
918 gint ty
= (gint
) event
->y
;
921 gtk_tree_view_get_path_at_pos(view
, tx
, ty
, &path
, &column
, &cx
,
924 gtk_tree_view_get_cursor(view
, &path
, &column
);
929 if (!gtk_tree_model_get_iter(model2
, &iter
, path
))
931 gtk_tree_model_get(model2
, &iter
, COL_MENU
, &menu
, -1);
933 col
= column2index(column
);
934 if (event
->type
== GDK_2BUTTON_PRESS
) {
935 enum prop_type ptype
;
936 ptype
= menu
->prompt
? menu
->prompt
->type
: P_UNKNOWN
;
938 if (ptype
== P_MENU
&& view_mode
!= FULL_VIEW
&& col
== COL_OPTION
) {
939 // goes down into menu
942 gtk_widget_set_sensitive(back_btn
, TRUE
);
943 } else if ((col
== COL_OPTION
)) {
944 toggle_sym_value(menu
);
945 gtk_tree_view_expand_row(view
, path
, TRUE
);
948 if (col
== COL_VALUE
) {
949 toggle_sym_value(menu
);
950 gtk_tree_view_expand_row(view
, path
, TRUE
);
951 } else if (col
== COL_NO
|| col
== COL_MOD
953 change_sym_value(menu
, col
);
954 gtk_tree_view_expand_row(view
, path
, TRUE
);
961 /* Key pressed: update choice */
963 on_treeview2_key_press_event(GtkWidget
* widget
,
964 GdkEventKey
* event
, gpointer user_data
)
966 GtkTreeView
*view
= GTK_TREE_VIEW(widget
);
968 GtkTreeViewColumn
*column
;
973 gtk_tree_view_get_cursor(view
, &path
, &column
);
977 if (event
->keyval
== GDK_space
) {
978 if (gtk_tree_view_row_expanded(view
, path
))
979 gtk_tree_view_collapse_row(view
, path
);
981 gtk_tree_view_expand_row(view
, path
, FALSE
);
984 if (event
->keyval
== GDK_KP_Enter
) {
986 if (widget
== tree1_w
)
989 gtk_tree_model_get_iter(model2
, &iter
, path
);
990 gtk_tree_model_get(model2
, &iter
, COL_MENU
, &menu
, -1);
992 if (!strcasecmp(event
->string
, "n"))
994 else if (!strcasecmp(event
->string
, "m"))
996 else if (!strcasecmp(event
->string
, "y"))
1000 change_sym_value(menu
, col
);
1006 /* Row selection changed: update help */
1008 on_treeview2_cursor_changed(GtkTreeView
* treeview
, gpointer user_data
)
1010 GtkTreeSelection
*selection
;
1014 selection
= gtk_tree_view_get_selection(treeview
);
1015 if (gtk_tree_selection_get_selected(selection
, &model2
, &iter
)) {
1016 gtk_tree_model_get(model2
, &iter
, COL_MENU
, &menu
, -1);
1017 text_insert_help(menu
);
1022 /* User click: display sub-tree in the right frame. */
1024 on_treeview1_button_press_event(GtkWidget
* widget
,
1025 GdkEventButton
* event
, gpointer user_data
)
1027 GtkTreeView
*view
= GTK_TREE_VIEW(widget
);
1029 GtkTreeViewColumn
*column
;
1033 gint tx
= (gint
) event
->x
;
1034 gint ty
= (gint
) event
->y
;
1037 gtk_tree_view_get_path_at_pos(view
, tx
, ty
, &path
, &column
, &cx
,
1042 gtk_tree_model_get_iter(model1
, &iter
, path
);
1043 gtk_tree_model_get(model1
, &iter
, COL_MENU
, &menu
, -1);
1045 if (event
->type
== GDK_2BUTTON_PRESS
) {
1046 toggle_sym_value(menu
);
1048 display_tree_part();
1051 display_tree_part();
1054 gtk_widget_realize(tree2_w
);
1055 gtk_tree_view_set_cursor(view
, path
, NULL
, FALSE
);
1056 gtk_widget_grab_focus(tree2_w
);
1062 /* Fill a row of strings */
1063 static gchar
**fill_row(struct menu
*menu
)
1065 static gchar
*row
[COL_NUMBER
];
1066 struct symbol
*sym
= menu
->sym
;
1070 enum prop_type ptype
;
1073 for (i
= COL_OPTION
; i
<= COL_COLOR
; i
++)
1075 bzero(row
, sizeof(row
));
1078 g_strdup_printf("%s %s", _(menu_get_prompt(menu
)),
1079 sym
&& !sym_has_value(sym
) ? "(NEW)" : "");
1081 if (opt_mode
== OPT_ALL
&& !menu_is_visible(menu
))
1082 row
[COL_COLOR
] = g_strdup("DarkGray");
1083 else if (opt_mode
== OPT_PROMPT
&&
1084 menu_has_prompt(menu
) && !menu_is_visible(menu
))
1085 row
[COL_COLOR
] = g_strdup("DarkGray");
1087 row
[COL_COLOR
] = g_strdup("Black");
1089 ptype
= menu
->prompt
? menu
->prompt
->type
: P_UNKNOWN
;
1092 row
[COL_PIXBUF
] = (gchar
*) xpm_menu
;
1093 if (view_mode
== SINGLE_VIEW
)
1094 row
[COL_PIXVIS
] = GINT_TO_POINTER(TRUE
);
1095 row
[COL_BTNVIS
] = GINT_TO_POINTER(FALSE
);
1098 row
[COL_PIXBUF
] = (gchar
*) xpm_void
;
1099 row
[COL_PIXVIS
] = GINT_TO_POINTER(FALSE
);
1100 row
[COL_BTNVIS
] = GINT_TO_POINTER(FALSE
);
1103 row
[COL_PIXBUF
] = (gchar
*) xpm_void
;
1104 row
[COL_PIXVIS
] = GINT_TO_POINTER(FALSE
);
1105 row
[COL_BTNVIS
] = GINT_TO_POINTER(TRUE
);
1111 row
[COL_NAME
] = g_strdup(sym
->name
);
1113 sym_calc_value(sym
);
1114 sym
->flags
&= ~SYMBOL_CHANGED
;
1116 if (sym_is_choice(sym
)) { // parse childs for getting final value
1118 struct symbol
*def_sym
= sym_get_choice_value(sym
);
1119 struct menu
*def_menu
= NULL
;
1121 row
[COL_BTNVIS
] = GINT_TO_POINTER(FALSE
);
1123 for (child
= menu
->list
; child
; child
= child
->next
) {
1124 if (menu_is_visible(child
)
1125 && child
->sym
== def_sym
)
1131 g_strdup(_(menu_get_prompt(def_menu
)));
1133 if (sym
->flags
& SYMBOL_CHOICEVAL
)
1134 row
[COL_BTNRAD
] = GINT_TO_POINTER(TRUE
);
1136 stype
= sym_get_type(sym
);
1139 if (GPOINTER_TO_INT(row
[COL_PIXVIS
]) == FALSE
)
1140 row
[COL_BTNVIS
] = GINT_TO_POINTER(TRUE
);
1141 if (sym_is_choice(sym
))
1145 val
= sym_get_tristate_value(sym
);
1148 row
[COL_NO
] = g_strdup("N");
1149 row
[COL_VALUE
] = g_strdup("N");
1150 row
[COL_BTNACT
] = GINT_TO_POINTER(FALSE
);
1151 row
[COL_BTNINC
] = GINT_TO_POINTER(FALSE
);
1154 row
[COL_MOD
] = g_strdup("M");
1155 row
[COL_VALUE
] = g_strdup("M");
1156 row
[COL_BTNINC
] = GINT_TO_POINTER(TRUE
);
1159 row
[COL_YES
] = g_strdup("Y");
1160 row
[COL_VALUE
] = g_strdup("Y");
1161 row
[COL_BTNACT
] = GINT_TO_POINTER(TRUE
);
1162 row
[COL_BTNINC
] = GINT_TO_POINTER(FALSE
);
1166 if (val
!= no
&& sym_tristate_within_range(sym
, no
))
1167 row
[COL_NO
] = g_strdup("_");
1168 if (val
!= mod
&& sym_tristate_within_range(sym
, mod
))
1169 row
[COL_MOD
] = g_strdup("_");
1170 if (val
!= yes
&& sym_tristate_within_range(sym
, yes
))
1171 row
[COL_YES
] = g_strdup("_");
1176 def
= sym_get_string_value(sym
);
1177 row
[COL_VALUE
] = g_strdup(def
);
1178 row
[COL_EDIT
] = GINT_TO_POINTER(TRUE
);
1179 row
[COL_BTNVIS
] = GINT_TO_POINTER(FALSE
);
1187 /* Set the node content with a row of strings */
1188 static void set_node(GtkTreeIter
* node
, struct menu
*menu
, gchar
** row
)
1194 pix
= gdk_pixbuf_new_from_xpm_data((const char **)
1197 gdk_color_parse(row
[COL_COLOR
], &color
);
1198 gdk_colormap_alloc_colors(gdk_colormap_get_system(), &color
, 1,
1199 FALSE
, FALSE
, &success
);
1201 gtk_tree_store_set(tree
, node
,
1202 COL_OPTION
, row
[COL_OPTION
],
1203 COL_NAME
, row
[COL_NAME
],
1204 COL_NO
, row
[COL_NO
],
1205 COL_MOD
, row
[COL_MOD
],
1206 COL_YES
, row
[COL_YES
],
1207 COL_VALUE
, row
[COL_VALUE
],
1208 COL_MENU
, (gpointer
) menu
,
1210 COL_EDIT
, GPOINTER_TO_INT(row
[COL_EDIT
]),
1212 COL_PIXVIS
, GPOINTER_TO_INT(row
[COL_PIXVIS
]),
1213 COL_BTNVIS
, GPOINTER_TO_INT(row
[COL_BTNVIS
]),
1214 COL_BTNACT
, GPOINTER_TO_INT(row
[COL_BTNACT
]),
1215 COL_BTNINC
, GPOINTER_TO_INT(row
[COL_BTNINC
]),
1216 COL_BTNRAD
, GPOINTER_TO_INT(row
[COL_BTNRAD
]),
1219 g_object_unref(pix
);
1223 /* Add a node to the tree */
1224 static void place_node(struct menu
*menu
, char **row
)
1226 GtkTreeIter
*parent
= parents
[indent
- 1];
1227 GtkTreeIter
*node
= parents
[indent
];
1229 gtk_tree_store_append(tree
, node
, parent
);
1230 set_node(node
, menu
, row
);
1234 /* Find a node in the GTK+ tree */
1235 static GtkTreeIter found
;
1238 * Find a menu in the GtkTree starting at parent.
1240 GtkTreeIter
*gtktree_iter_find_node(GtkTreeIter
* parent
,
1241 struct menu
*tofind
)
1244 GtkTreeIter
*child
= &iter
;
1248 valid
= gtk_tree_model_iter_children(model2
, child
, parent
);
1252 gtk_tree_model_get(model2
, child
, 6, &menu
, -1);
1254 if (menu
== tofind
) {
1255 memcpy(&found
, child
, sizeof(GtkTreeIter
));
1259 ret
= gtktree_iter_find_node(child
, tofind
);
1263 valid
= gtk_tree_model_iter_next(model2
, child
);
1271 * Update the tree by adding/removing entries
1272 * Does not change other nodes
1274 static void update_tree(struct menu
*src
, GtkTreeIter
* dst
)
1276 struct menu
*child1
;
1277 GtkTreeIter iter
, tmp
;
1278 GtkTreeIter
*child2
= &iter
;
1280 GtkTreeIter
*sibling
;
1282 struct menu
*menu1
, *menu2
;
1284 if (src
== &rootmenu
)
1287 valid
= gtk_tree_model_iter_children(model2
, child2
, dst
);
1288 for (child1
= src
->list
; child1
; child1
= child1
->next
) {
1295 gtk_tree_model_get(model2
, child2
, COL_MENU
,
1298 menu2
= NULL
; // force adding of a first child
1301 printf("%*c%s | %s\n", indent
, ' ',
1302 menu1
? menu_get_prompt(menu1
) : "nil",
1303 menu2
? menu_get_prompt(menu2
) : "nil");
1306 if ((opt_mode
== OPT_NORMAL
&& !menu_is_visible(child1
)) ||
1307 (opt_mode
== OPT_PROMPT
&& !menu_has_prompt(child1
)) ||
1308 (opt_mode
== OPT_ALL
&& !menu_get_prompt(child1
))) {
1311 if (gtktree_iter_find_node(dst
, menu1
) != NULL
) {
1312 memcpy(&tmp
, child2
, sizeof(GtkTreeIter
));
1313 valid
= gtk_tree_model_iter_next(model2
,
1315 gtk_tree_store_remove(tree2
, &tmp
);
1317 return; /* next parent */
1319 goto reparse
; /* next child */
1324 if (menu1
!= menu2
) {
1325 if (gtktree_iter_find_node(dst
, menu1
) == NULL
) { // add node
1326 if (!valid
&& !menu2
)
1330 gtk_tree_store_insert_before(tree2
,
1333 set_node(child2
, menu1
, fill_row(menu1
));
1336 } else { // remove node
1337 memcpy(&tmp
, child2
, sizeof(GtkTreeIter
));
1338 valid
= gtk_tree_model_iter_next(model2
,
1340 gtk_tree_store_remove(tree2
, &tmp
);
1342 return; // next parent
1344 goto reparse
; // next child
1346 } else if (sym
&& (sym
->flags
& SYMBOL_CHANGED
)) {
1347 set_node(child2
, menu1
, fill_row(menu1
));
1351 update_tree(child1
, child2
);
1354 valid
= gtk_tree_model_iter_next(model2
, child2
);
1359 /* Display the whole tree (single/split/full view) */
1360 static void display_tree(struct menu
*menu
)
1363 struct property
*prop
;
1365 enum prop_type ptype
;
1367 if (menu
== &rootmenu
) {
1369 current
= &rootmenu
;
1372 for (child
= menu
->list
; child
; child
= child
->next
) {
1373 prop
= child
->prompt
;
1375 ptype
= prop
? prop
->type
: P_UNKNOWN
;
1378 sym
->flags
&= ~SYMBOL_CHANGED
;
1380 if ((view_mode
== SPLIT_VIEW
)
1381 && !(child
->flags
& MENU_ROOT
) && (tree
== tree1
))
1384 if ((view_mode
== SPLIT_VIEW
) && (child
->flags
& MENU_ROOT
)
1388 if ((opt_mode
== OPT_NORMAL
&& menu_is_visible(child
)) ||
1389 (opt_mode
== OPT_PROMPT
&& menu_has_prompt(child
)) ||
1390 (opt_mode
== OPT_ALL
&& menu_get_prompt(child
)))
1391 place_node(child
, fill_row(child
));
1393 printf("%*c%s: ", indent
, ' ', menu_get_prompt(child
));
1394 printf("%s", child
->flags
& MENU_ROOT
? "rootmenu | " : "");
1395 printf("%s", prop_get_type_name(ptype
));
1398 printf("%s", sym_type_name(sym
->type
));
1400 printf("%s", dbg_sym_flags(sym
->flags
));
1405 if ((view_mode
!= FULL_VIEW
) && (ptype
== P_MENU
)
1409 if (((menu != &rootmenu) && !(menu->flags & MENU_ROOT))
1410 || (view_mode == FULL_VIEW)
1411 || (view_mode == SPLIT_VIEW))*/
1413 /* Change paned position if the view is not in 'split mode' */
1414 if (view_mode
== SINGLE_VIEW
|| view_mode
== FULL_VIEW
) {
1415 gtk_paned_set_position(GTK_PANED(hpaned
), 0);
1418 if (((view_mode
== SINGLE_VIEW
) && (menu
->flags
& MENU_ROOT
))
1419 || (view_mode
== FULL_VIEW
)
1420 || (view_mode
== SPLIT_VIEW
)) {
1422 display_tree(child
);
1428 /* Display a part of the tree starting at current node (single/split view) */
1429 static void display_tree_part(void)
1432 gtk_tree_store_clear(tree2
);
1433 if (view_mode
== SINGLE_VIEW
)
1434 display_tree(current
);
1435 else if (view_mode
== SPLIT_VIEW
)
1436 display_tree(browsed
);
1437 gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w
));
1440 /* Display the list in the left frame (split view) */
1441 static void display_list(void)
1444 gtk_tree_store_clear(tree1
);
1447 display_tree(&rootmenu
);
1448 gtk_tree_view_expand_all(GTK_TREE_VIEW(tree1_w
));
1452 void fixup_rootmenu(struct menu
*menu
)
1455 static int menu_cnt
= 0;
1457 menu
->flags
|= MENU_ROOT
;
1458 for (child
= menu
->list
; child
; child
= child
->next
) {
1459 if (child
->prompt
&& child
->prompt
->type
== P_MENU
) {
1461 fixup_rootmenu(child
);
1463 } else if (!menu_cnt
)
1464 fixup_rootmenu(child
);
1470 int main(int ac
, char *av
[])
1476 bindtextdomain(PACKAGE
, LOCALEDIR
);
1477 bind_textdomain_codeset(PACKAGE
, "UTF-8");
1478 textdomain(PACKAGE
);
1485 //add_pixmap_directory (PACKAGE_DATA_DIR "/" PACKAGE "/pixmaps");
1486 //add_pixmap_directory (PACKAGE_SOURCE_DIR "/pixmaps");
1488 /* Determine GUI path */
1489 env
= getenv(SRCTREE
);
1491 glade_file
= g_strconcat(env
, "/scripts/kconfig/gconf.glade", NULL
);
1492 else if (av
[0][0] == '/')
1493 glade_file
= g_strconcat(av
[0], ".glade", NULL
);
1495 glade_file
= g_strconcat(g_get_current_dir(), "/", av
[0], ".glade", NULL
);
1498 if (ac
> 1 && av
[1][0] == '-') {
1505 printf("%s <config>\n", av
[0]);
1513 fixup_rootmenu(&rootmenu
);
1516 /* Load the interface and connect signals */
1517 init_main_window(glade_file
);
1522 switch (view_mode
) {
1524 display_tree_part();
1530 display_tree(&rootmenu
);
1539 static void conf_changed(void)
1541 bool changed
= conf_get_changed();
1542 gtk_widget_set_sensitive(save_btn
, changed
);
1543 gtk_widget_set_sensitive(save_menu_item
, changed
);