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.
16 #include <glade/glade.h>
19 #include <gdk/gdkkeysyms.h>
30 SINGLE_VIEW
, SPLIT_VIEW
, FULL_VIEW
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 "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
;
57 GtkTreeStore
*tree1
, *tree2
, *tree
;
58 GtkTreeModel
*model1
, *model2
;
59 static GtkTreeIter
*parents
[256];
62 static struct menu
*current
; // current node for SINGLE view
63 static struct menu
*browsed
; // browsed node for SPLIT view
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
,
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
)
90 strcpy(buf
, "unknown");
92 strcpy(buf
, "boolean");
93 if (val
== S_TRISTATE
)
94 strcpy(buf
, "tristate");
100 strcpy(buf
, "string");
102 strcpy(buf
, "other");
111 const char *dbg_print_flags(int val
)
113 static char buf
[256];
117 if (val
& SYMBOL_YES
)
119 if (val
& SYMBOL_MOD
)
123 if (val
& SYMBOL_CONST
)
124 strcat(buf
, "const/");
125 if (val
& SYMBOL_CHECK
)
126 strcat(buf
, "check/");
127 if (val
& SYMBOL_CHOICE
)
128 strcat(buf
, "choice/");
129 if (val
& SYMBOL_CHOICEVAL
)
130 strcat(buf
, "choiceval/");
131 if (val
& SYMBOL_PRINTED
)
132 strcat(buf
, "printed/");
133 if (val
& SYMBOL_VALID
)
134 strcat(buf
, "valid/");
135 if (val
& SYMBOL_OPTIONAL
)
136 strcat(buf
, "optional/");
137 if (val
& SYMBOL_WRITE
)
138 strcat(buf
, "write/");
139 if (val
& SYMBOL_CHANGED
)
140 strcat(buf
, "changed/");
141 if (val
& SYMBOL_NEW
)
143 if (val
& SYMBOL_AUTO
)
144 strcat(buf
, "auto/");
146 buf
[strlen(buf
) - 1] = '\0';
154 const char *dbg_print_ptype(int val
)
156 static char buf
[256];
160 if (val
== P_UNKNOWN
)
161 strcpy(buf
, "unknown");
163 strcpy(buf
, "prompt");
164 if (val
== P_COMMENT
)
165 strcpy(buf
, "comment");
168 if (val
== P_DEFAULT
)
169 strcpy(buf
, "default");
171 strcpy(buf
, "choice");
181 /* Main Window Initialization */
184 void init_main_window(const gchar
* glade_file
)
188 GtkTextBuffer
*txtbuf
;
194 xml
= glade_xml_new(glade_file
, "window1", NULL
);
196 g_error("GUI loading failed !\n");
197 glade_xml_signal_autoconnect(xml
);
199 main_wnd
= glade_xml_get_widget(xml
, "window1");
200 hpaned
= glade_xml_get_widget(xml
, "hpaned1");
201 vpaned
= glade_xml_get_widget(xml
, "vpaned1");
202 tree1_w
= glade_xml_get_widget(xml
, "treeview1");
203 tree2_w
= glade_xml_get_widget(xml
, "treeview2");
204 text_w
= glade_xml_get_widget(xml
, "textview3");
206 back_btn
= glade_xml_get_widget(xml
, "button1");
207 gtk_widget_set_sensitive(back_btn
, FALSE
);
209 widget
= glade_xml_get_widget(xml
, "show_name1");
210 gtk_check_menu_item_set_active((GtkCheckMenuItem
*) widget
,
213 widget
= glade_xml_get_widget(xml
, "show_range1");
214 gtk_check_menu_item_set_active((GtkCheckMenuItem
*) widget
,
217 widget
= glade_xml_get_widget(xml
, "show_data1");
218 gtk_check_menu_item_set_active((GtkCheckMenuItem
*) widget
,
221 style
= gtk_widget_get_style(main_wnd
);
222 widget
= glade_xml_get_widget(xml
, "toolbar1");
224 pixmap
= gdk_pixmap_create_from_xpm_d(main_wnd
->window
, &mask
,
225 &style
->bg
[GTK_STATE_NORMAL
],
226 (gchar
**) xpm_single_view
);
227 gtk_image_set_from_pixmap(GTK_IMAGE
229 *) (g_list_nth(GTK_TOOLBAR(widget
)->
234 gdk_pixmap_create_from_xpm_d(main_wnd
->window
, &mask
,
235 &style
->bg
[GTK_STATE_NORMAL
],
236 (gchar
**) xpm_split_view
);
237 gtk_image_set_from_pixmap(GTK_IMAGE
239 *) (g_list_nth(GTK_TOOLBAR(widget
)->
244 gdk_pixmap_create_from_xpm_d(main_wnd
->window
, &mask
,
245 &style
->bg
[GTK_STATE_NORMAL
],
246 (gchar
**) xpm_tree_view
);
247 gtk_image_set_from_pixmap(GTK_IMAGE
249 *) (g_list_nth(GTK_TOOLBAR(widget
)->
256 widget
= glade_xml_get_widget(xml
, "button4");
257 gtk_button_clicked(GTK_BUTTON(widget
));
260 widget
= glade_xml_get_widget(xml
, "button5");
261 gtk_button_clicked(GTK_BUTTON(widget
));
264 widget
= glade_xml_get_widget(xml
, "button6");
265 gtk_button_clicked(GTK_BUTTON(widget
));
269 txtbuf
= gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w
));
270 tag1
= gtk_text_buffer_create_tag(txtbuf
, "mytag1",
272 "weight", PANGO_WEIGHT_BOLD
,
274 tag2
= gtk_text_buffer_create_tag(txtbuf
, "mytag2",
275 /*"style", PANGO_STYLE_OBLIQUE, */
278 sprintf(title
, "Linux Kernel v%s Configuration",
279 getenv("KERNELRELEASE"));
280 gtk_window_set_title(GTK_WINDOW(main_wnd
), title
);
282 gtk_widget_show(main_wnd
);
285 void init_tree_model(void)
289 tree
= tree2
= gtk_tree_store_new(COL_NUMBER
,
290 G_TYPE_STRING
, G_TYPE_STRING
,
291 G_TYPE_STRING
, G_TYPE_STRING
,
292 G_TYPE_STRING
, G_TYPE_STRING
,
293 G_TYPE_POINTER
, GDK_TYPE_COLOR
,
294 G_TYPE_BOOLEAN
, GDK_TYPE_PIXBUF
,
295 G_TYPE_BOOLEAN
, G_TYPE_BOOLEAN
,
296 G_TYPE_BOOLEAN
, G_TYPE_BOOLEAN
,
298 model2
= GTK_TREE_MODEL(tree2
);
300 for (parents
[0] = NULL
, i
= 1; i
< 256; i
++)
301 parents
[i
] = (GtkTreeIter
*) g_malloc(sizeof(GtkTreeIter
));
303 tree1
= gtk_tree_store_new(COL_NUMBER
,
304 G_TYPE_STRING
, G_TYPE_STRING
,
305 G_TYPE_STRING
, G_TYPE_STRING
,
306 G_TYPE_STRING
, G_TYPE_STRING
,
307 G_TYPE_POINTER
, GDK_TYPE_COLOR
,
308 G_TYPE_BOOLEAN
, GDK_TYPE_PIXBUF
,
309 G_TYPE_BOOLEAN
, G_TYPE_BOOLEAN
,
310 G_TYPE_BOOLEAN
, G_TYPE_BOOLEAN
,
312 model1
= GTK_TREE_MODEL(tree1
);
315 void init_left_tree(void)
317 GtkTreeView
*view
= GTK_TREE_VIEW(tree1_w
);
318 GtkCellRenderer
*renderer
;
319 GtkTreeSelection
*sel
;
320 GtkTreeViewColumn
*column
;
322 gtk_tree_view_set_model(view
, model1
);
323 gtk_tree_view_set_headers_visible(view
, TRUE
);
324 gtk_tree_view_set_rules_hint(view
, FALSE
);
326 column
= gtk_tree_view_column_new();
327 gtk_tree_view_append_column(view
, column
);
328 gtk_tree_view_column_set_title(column
, "Options");
330 renderer
= gtk_cell_renderer_toggle_new();
331 gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column
),
333 gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column
),
335 "active", COL_BTNACT
,
336 "inconsistent", COL_BTNINC
,
337 "visible", COL_BTNVIS
,
338 "radio", COL_BTNRAD
, NULL
);
339 renderer
= gtk_cell_renderer_text_new();
340 gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column
),
342 gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column
),
348 sel
= gtk_tree_view_get_selection(view
);
349 gtk_tree_selection_set_mode(sel
, GTK_SELECTION_SINGLE
);
350 gtk_widget_realize(tree1_w
);
353 static void renderer_edited(GtkCellRendererText
* cell
,
354 const gchar
* path_string
,
355 const gchar
* new_text
, gpointer user_data
);
356 static void renderer_toggled(GtkCellRendererToggle
* cellrenderertoggle
,
357 gchar
* arg1
, gpointer user_data
);
359 void init_right_tree(void)
361 GtkTreeView
*view
= GTK_TREE_VIEW(tree2_w
);
362 GtkCellRenderer
*renderer
;
363 GtkTreeSelection
*sel
;
364 GtkTreeViewColumn
*column
;
367 gtk_tree_view_set_model(view
, model2
);
368 gtk_tree_view_set_headers_visible(view
, TRUE
);
369 gtk_tree_view_set_rules_hint(view
, FALSE
);
371 column
= gtk_tree_view_column_new();
372 gtk_tree_view_append_column(view
, column
);
373 gtk_tree_view_column_set_title(column
, "Options");
375 renderer
= gtk_cell_renderer_pixbuf_new();
376 gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column
),
378 gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column
),
380 "pixbuf", COL_PIXBUF
,
381 "visible", COL_PIXVIS
, NULL
);
382 renderer
= gtk_cell_renderer_toggle_new();
383 gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column
),
385 gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column
),
387 "active", COL_BTNACT
,
388 "inconsistent", COL_BTNINC
,
389 "visible", COL_BTNVIS
,
390 "radio", COL_BTNRAD
, NULL
);
391 /*g_signal_connect(G_OBJECT(renderer), "toggled",
392 G_CALLBACK(renderer_toggled), NULL); */
393 renderer
= gtk_cell_renderer_text_new();
394 gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column
),
396 gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column
),
402 renderer
= gtk_cell_renderer_text_new();
403 gtk_tree_view_insert_column_with_attributes(view
, -1,
408 renderer
= gtk_cell_renderer_text_new();
409 gtk_tree_view_insert_column_with_attributes(view
, -1,
414 renderer
= gtk_cell_renderer_text_new();
415 gtk_tree_view_insert_column_with_attributes(view
, -1,
420 renderer
= gtk_cell_renderer_text_new();
421 gtk_tree_view_insert_column_with_attributes(view
, -1,
426 renderer
= gtk_cell_renderer_text_new();
427 gtk_tree_view_insert_column_with_attributes(view
, -1,
434 g_signal_connect(G_OBJECT(renderer
), "edited",
435 G_CALLBACK(renderer_edited
), NULL
);
437 column
= gtk_tree_view_get_column(view
, COL_NAME
);
438 gtk_tree_view_column_set_visible(column
, show_name
);
439 column
= gtk_tree_view_get_column(view
, COL_NO
);
440 gtk_tree_view_column_set_visible(column
, show_range
);
441 column
= gtk_tree_view_get_column(view
, COL_MOD
);
442 gtk_tree_view_column_set_visible(column
, show_range
);
443 column
= gtk_tree_view_get_column(view
, COL_YES
);
444 gtk_tree_view_column_set_visible(column
, show_range
);
445 column
= gtk_tree_view_get_column(view
, COL_VALUE
);
446 gtk_tree_view_column_set_visible(column
, show_value
);
449 for (i
= 0; i
< COL_VALUE
; i
++) {
450 column
= gtk_tree_view_get_column(view
, i
);
451 gtk_tree_view_column_set_resizable(column
, TRUE
);
455 sel
= gtk_tree_view_get_selection(view
);
456 gtk_tree_selection_set_mode(sel
, GTK_SELECTION_SINGLE
);
460 /* Utility Functions */
463 static void text_insert_help(struct menu
*menu
)
465 GtkTextBuffer
*buffer
;
466 GtkTextIter start
, end
;
467 const char *prompt
= menu_get_prompt(menu
);
469 const char *help
= nohelp_text
;
473 else if (menu
->sym
->help
)
474 help
= menu
->sym
->help
;
476 if (menu
->sym
&& menu
->sym
->name
)
477 name
= g_strdup_printf(menu
->sym
->name
);
481 buffer
= gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w
));
482 gtk_text_buffer_get_bounds(buffer
, &start
, &end
);
483 gtk_text_buffer_delete(buffer
, &start
, &end
);
484 gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_w
), 15);
486 gtk_text_buffer_get_end_iter(buffer
, &end
);
487 gtk_text_buffer_insert_with_tags(buffer
, &end
, prompt
, -1, tag1
,
489 gtk_text_buffer_insert_at_cursor(buffer
, " ", 1);
490 gtk_text_buffer_get_end_iter(buffer
, &end
);
491 gtk_text_buffer_insert_with_tags(buffer
, &end
, name
, -1, tag1
,
493 gtk_text_buffer_insert_at_cursor(buffer
, "\n\n", 2);
494 gtk_text_buffer_get_end_iter(buffer
, &end
);
495 gtk_text_buffer_insert_with_tags(buffer
, &end
, help
, -1, tag2
,
500 static void text_insert_msg(const char *title
, const char *message
)
502 GtkTextBuffer
*buffer
;
503 GtkTextIter start
, end
;
504 const char *msg
= message
;
506 buffer
= gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w
));
507 gtk_text_buffer_get_bounds(buffer
, &start
, &end
);
508 gtk_text_buffer_delete(buffer
, &start
, &end
);
509 gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_w
), 15);
511 gtk_text_buffer_get_end_iter(buffer
, &end
);
512 gtk_text_buffer_insert_with_tags(buffer
, &end
, title
, -1, tag1
,
514 gtk_text_buffer_insert_at_cursor(buffer
, "\n\n", 2);
515 gtk_text_buffer_get_end_iter(buffer
, &end
);
516 gtk_text_buffer_insert_with_tags(buffer
, &end
, msg
, -1, tag2
,
521 /* Main Windows Callbacks */
523 void on_save1_activate(GtkMenuItem
* menuitem
, gpointer user_data
);
524 gboolean
on_window1_delete_event(GtkWidget
* widget
, GdkEvent
* event
,
527 GtkWidget
*dialog
, *label
;
530 if (config_changed
== FALSE
)
533 dialog
= gtk_dialog_new_with_buttons("Warning !",
534 GTK_WINDOW(main_wnd
),
537 GTK_DIALOG_DESTROY_WITH_PARENT
),
543 GTK_RESPONSE_CANCEL
, NULL
);
544 gtk_dialog_set_default_response(GTK_DIALOG(dialog
),
545 GTK_RESPONSE_CANCEL
);
547 label
= gtk_label_new("\nSave configuration ?\n");
548 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog
)->vbox
), label
);
549 gtk_widget_show(label
);
551 result
= gtk_dialog_run(GTK_DIALOG(dialog
));
553 case GTK_RESPONSE_YES
:
554 on_save1_activate(NULL
, NULL
);
556 case GTK_RESPONSE_NO
:
558 case GTK_RESPONSE_CANCEL
:
559 case GTK_RESPONSE_DELETE_EVENT
:
561 gtk_widget_destroy(dialog
);
569 void on_window1_destroy(GtkObject
* object
, gpointer user_data
)
576 on_window1_size_request(GtkWidget
* widget
,
577 GtkRequisition
* requisition
, gpointer user_data
)
582 if (widget
->window
== NULL
)
583 gtk_window_get_default_size(GTK_WINDOW(main_wnd
), &w
, &h
);
585 gdk_window_get_size(widget
->window
, &w
, &h
);
591 gtk_paned_set_position(GTK_PANED(vpaned
), 2 * h
/ 3);
595 /* Menu & Toolbar Callbacks */
599 load_filename(GtkFileSelection
* file_selector
, gpointer user_data
)
603 fn
= gtk_file_selection_get_filename(GTK_FILE_SELECTION
607 text_insert_msg("Error", "Unable to load configuration !");
609 display_tree(&rootmenu
);
612 void on_load1_activate(GtkMenuItem
* menuitem
, gpointer user_data
)
616 fs
= gtk_file_selection_new("Load file...");
617 g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs
)->ok_button
),
619 G_CALLBACK(load_filename
), (gpointer
) fs
);
620 g_signal_connect_swapped(GTK_OBJECT
621 (GTK_FILE_SELECTION(fs
)->ok_button
),
622 "clicked", G_CALLBACK(gtk_widget_destroy
),
624 g_signal_connect_swapped(GTK_OBJECT
625 (GTK_FILE_SELECTION(fs
)->cancel_button
),
626 "clicked", G_CALLBACK(gtk_widget_destroy
),
632 void on_save1_activate(GtkMenuItem
* menuitem
, gpointer user_data
)
634 if (conf_write(NULL
))
635 text_insert_msg("Error", "Unable to save configuration !");
637 config_changed
= FALSE
;
642 store_filename(GtkFileSelection
* file_selector
, gpointer user_data
)
646 fn
= gtk_file_selection_get_filename(GTK_FILE_SELECTION
650 text_insert_msg("Error", "Unable to save configuration !");
652 gtk_widget_destroy(GTK_WIDGET(user_data
));
655 void on_save_as1_activate(GtkMenuItem
* menuitem
, gpointer user_data
)
659 fs
= gtk_file_selection_new("Save file as...");
660 g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs
)->ok_button
),
662 G_CALLBACK(store_filename
), (gpointer
) fs
);
663 g_signal_connect_swapped(GTK_OBJECT
664 (GTK_FILE_SELECTION(fs
)->ok_button
),
665 "clicked", G_CALLBACK(gtk_widget_destroy
),
667 g_signal_connect_swapped(GTK_OBJECT
668 (GTK_FILE_SELECTION(fs
)->cancel_button
),
669 "clicked", G_CALLBACK(gtk_widget_destroy
),
675 void on_quit1_activate(GtkMenuItem
* menuitem
, gpointer user_data
)
677 if (!on_window1_delete_event(NULL
, NULL
, NULL
))
678 gtk_widget_destroy(GTK_WIDGET(main_wnd
));
682 void on_show_name1_activate(GtkMenuItem
* menuitem
, gpointer user_data
)
684 GtkTreeViewColumn
*col
;
686 show_name
= GTK_CHECK_MENU_ITEM(menuitem
)->active
;
687 col
= gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w
), COL_NAME
);
689 gtk_tree_view_column_set_visible(col
, show_name
);
693 void on_show_range1_activate(GtkMenuItem
* menuitem
, gpointer user_data
)
695 GtkTreeViewColumn
*col
;
697 show_range
= GTK_CHECK_MENU_ITEM(menuitem
)->active
;
698 col
= gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w
), COL_NO
);
700 gtk_tree_view_column_set_visible(col
, show_range
);
701 col
= gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w
), COL_MOD
);
703 gtk_tree_view_column_set_visible(col
, show_range
);
704 col
= gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w
), COL_YES
);
706 gtk_tree_view_column_set_visible(col
, show_range
);
711 void on_show_data1_activate(GtkMenuItem
* menuitem
, gpointer user_data
)
713 GtkTreeViewColumn
*col
;
715 show_value
= GTK_CHECK_MENU_ITEM(menuitem
)->active
;
716 col
= gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w
), COL_VALUE
);
718 gtk_tree_view_column_set_visible(col
, show_value
);
723 on_show_all_options1_activate(GtkMenuItem
* menuitem
, gpointer user_data
)
725 show_all
= GTK_CHECK_MENU_ITEM(menuitem
)->active
;
727 gtk_tree_store_clear(tree2
);
728 display_tree(&rootmenu
); // instead of update_tree to speed-up
733 on_show_debug_info1_activate(GtkMenuItem
* menuitem
, gpointer user_data
)
735 show_debug
= GTK_CHECK_MENU_ITEM(menuitem
)->active
;
736 update_tree(&rootmenu
, NULL
);
740 void on_introduction1_activate(GtkMenuItem
* menuitem
, gpointer user_data
)
743 const gchar
*intro_text
=
744 "Welcome to gkc, the GTK+ graphical kernel configuration tool\n"
746 "For each option, a blank box indicates the feature is disabled, a\n"
747 "check indicates it is enabled, and a dot indicates that it is to\n"
748 "be compiled as a module. Clicking on the box will cycle through the three states.\n"
750 "If you do not see an option (e.g., a device driver) that you\n"
751 "believe should be present, try turning on Show All Options\n"
752 "under the Options menu.\n"
753 "Although there is no cross reference yet to help you figure out\n"
754 "what other options must be enabled to support the option you\n"
755 "are interested in, you can still view the help of a grayed-out\n"
758 "Toggling Show Debug Info under the Options menu will show \n"
759 "the dependencies, which you can then match by examining other options.";
761 dialog
= gtk_message_dialog_new(GTK_WINDOW(main_wnd
),
762 GTK_DIALOG_DESTROY_WITH_PARENT
,
764 GTK_BUTTONS_CLOSE
, intro_text
);
765 g_signal_connect_swapped(GTK_OBJECT(dialog
), "response",
766 G_CALLBACK(gtk_widget_destroy
),
768 gtk_widget_show_all(dialog
);
772 void on_about1_activate(GtkMenuItem
* menuitem
, gpointer user_data
)
775 const gchar
*about_text
=
776 "gkc is copyright (c) 2002 Romain Lievin <roms@lpg.ticalc.org>.\n"
777 "Based on the source code from Roman Zippel.\n";
779 dialog
= gtk_message_dialog_new(GTK_WINDOW(main_wnd
),
780 GTK_DIALOG_DESTROY_WITH_PARENT
,
782 GTK_BUTTONS_CLOSE
, about_text
);
783 g_signal_connect_swapped(GTK_OBJECT(dialog
), "response",
784 G_CALLBACK(gtk_widget_destroy
),
786 gtk_widget_show_all(dialog
);
790 void on_license1_activate(GtkMenuItem
* menuitem
, gpointer user_data
)
793 const gchar
*license_text
=
794 "gkc is released under the terms of the GNU GPL v2.\n"
795 "For more information, please see the source code or\n"
796 "visit http://www.fsf.org/licenses/licenses.html\n";
798 dialog
= gtk_message_dialog_new(GTK_WINDOW(main_wnd
),
799 GTK_DIALOG_DESTROY_WITH_PARENT
,
801 GTK_BUTTONS_CLOSE
, license_text
);
802 g_signal_connect_swapped(GTK_OBJECT(dialog
), "response",
803 G_CALLBACK(gtk_widget_destroy
),
805 gtk_widget_show_all(dialog
);
809 void on_back_pressed(GtkButton
* button
, gpointer user_data
)
811 enum prop_type ptype
;
813 current
= current
->parent
;
814 ptype
= current
->prompt
? current
->prompt
->type
: P_UNKNOWN
;
816 current
= current
->parent
;
819 if (current
== &rootmenu
)
820 gtk_widget_set_sensitive(back_btn
, FALSE
);
824 void on_load_pressed(GtkButton
* button
, gpointer user_data
)
826 on_load1_activate(NULL
, user_data
);
830 void on_save_pressed(GtkButton
* button
, gpointer user_data
)
832 on_save1_activate(NULL
, user_data
);
836 void on_single_clicked(GtkButton
* button
, gpointer user_data
)
838 view_mode
= SINGLE_VIEW
;
839 gtk_paned_set_position(GTK_PANED(hpaned
), 0);
840 gtk_widget_hide(tree1_w
);
846 void on_split_clicked(GtkButton
* button
, gpointer user_data
)
849 view_mode
= SPLIT_VIEW
;
850 gtk_widget_show(tree1_w
);
851 gtk_window_get_default_size(GTK_WINDOW(main_wnd
), &w
, &h
);
852 gtk_paned_set_position(GTK_PANED(hpaned
), w
/ 2);
854 gtk_tree_store_clear(tree2
);
859 void on_full_clicked(GtkButton
* button
, gpointer user_data
)
861 view_mode
= FULL_VIEW
;
862 gtk_paned_set_position(GTK_PANED(hpaned
), 0);
863 gtk_widget_hide(tree1_w
);
865 gtk_tree_store_clear(tree2
);
866 display_tree(&rootmenu
);
867 gtk_widget_set_sensitive(back_btn
, FALSE
);
871 void on_collapse_pressed(GtkButton
* button
, gpointer user_data
)
873 gtk_tree_view_collapse_all(GTK_TREE_VIEW(tree2_w
));
877 void on_expand_pressed(GtkButton
* button
, gpointer user_data
)
879 gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w
));
883 /* CTree Callbacks */
885 /* Change hex/int/string value in the cell */
886 static void renderer_edited(GtkCellRendererText
* cell
,
887 const gchar
* path_string
,
888 const gchar
* new_text
, gpointer user_data
)
890 GtkTreePath
*path
= gtk_tree_path_new_from_string(path_string
);
892 const char *old_def
, *new_def
;
896 if (!gtk_tree_model_get_iter(model2
, &iter
, path
))
899 gtk_tree_model_get(model2
, &iter
, COL_MENU
, &menu
, -1);
902 gtk_tree_model_get(model2
, &iter
, COL_VALUE
, &old_def
, -1);
905 sym_set_string_value(sym
, new_def
);
907 config_changed
= TRUE
;
908 update_tree(&rootmenu
, NULL
);
910 gtk_tree_path_free(path
);
913 /* Change the value of a symbol and update the tree */
914 static void change_sym_value(struct menu
*menu
, gint col
)
916 struct symbol
*sym
= menu
->sym
;
917 tristate oldval
, newval
;
924 else if (col
== COL_MOD
)
926 else if (col
== COL_YES
)
931 switch (sym_get_type(sym
)) {
934 oldval
= sym_get_tristate_value(sym
);
935 if (!sym_tristate_within_range(sym
, newval
))
937 sym_set_tristate_value(sym
, newval
);
938 config_changed
= TRUE
;
939 if (view_mode
== FULL_VIEW
)
940 update_tree(&rootmenu
, NULL
);
941 else if (view_mode
== SPLIT_VIEW
) {
942 update_tree(browsed
, NULL
);
945 else if (view_mode
== SINGLE_VIEW
)
946 display_tree_part(); //fixme: keep exp/coll
956 static void toggle_sym_value(struct menu
*menu
)
961 sym_toggle_tristate_value(menu
->sym
);
962 if (view_mode
== FULL_VIEW
)
963 update_tree(&rootmenu
, NULL
);
964 else if (view_mode
== SPLIT_VIEW
) {
965 update_tree(browsed
, NULL
);
968 else if (view_mode
== SINGLE_VIEW
)
969 display_tree_part(); //fixme: keep exp/coll
972 static void renderer_toggled(GtkCellRendererToggle
* cell
,
973 gchar
* path_string
, gpointer user_data
)
975 GtkTreePath
*path
, *sel_path
= NULL
;
976 GtkTreeIter iter
, sel_iter
;
977 GtkTreeSelection
*sel
;
980 path
= gtk_tree_path_new_from_string(path_string
);
981 if (!gtk_tree_model_get_iter(model2
, &iter
, path
))
984 sel
= gtk_tree_view_get_selection(GTK_TREE_VIEW(tree2_w
));
985 if (gtk_tree_selection_get_selected(sel
, NULL
, &sel_iter
))
986 sel_path
= gtk_tree_model_get_path(model2
, &sel_iter
);
989 if (gtk_tree_path_compare(path
, sel_path
))
992 gtk_tree_model_get(model2
, &iter
, COL_MENU
, &menu
, -1);
993 toggle_sym_value(menu
);
996 gtk_tree_path_free(sel_path
);
998 gtk_tree_path_free(path
);
1001 static gint
column2index(GtkTreeViewColumn
* column
)
1005 for (i
= 0; i
< COL_NUMBER
; i
++) {
1006 GtkTreeViewColumn
*col
;
1008 col
= gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w
), i
);
1017 /* User click: update choice (full) or goes down (single) */
1019 on_treeview2_button_press_event(GtkWidget
* widget
,
1020 GdkEventButton
* event
, gpointer user_data
)
1022 GtkTreeView
*view
= GTK_TREE_VIEW(widget
);
1024 GtkTreeViewColumn
*column
;
1029 #if GTK_CHECK_VERSION(2,1,4) // bug in ctree with earlier version of GTK
1030 gint tx
= (gint
) event
->x
;
1031 gint ty
= (gint
) event
->y
;
1034 gtk_tree_view_get_path_at_pos(view
, tx
, ty
, &path
, &column
, &cx
,
1037 gtk_tree_view_get_cursor(view
, &path
, &column
);
1042 if (!gtk_tree_model_get_iter(model2
, &iter
, path
))
1044 gtk_tree_model_get(model2
, &iter
, COL_MENU
, &menu
, -1);
1046 col
= column2index(column
);
1047 if (event
->type
== GDK_2BUTTON_PRESS
) {
1048 enum prop_type ptype
;
1049 ptype
= menu
->prompt
? menu
->prompt
->type
: P_UNKNOWN
;
1051 if (ptype
== P_MENU
&& view_mode
!= FULL_VIEW
&& col
== COL_OPTION
) {
1052 // goes down into menu
1054 display_tree_part();
1055 gtk_widget_set_sensitive(back_btn
, TRUE
);
1056 } else if ((col
== COL_OPTION
)) {
1057 toggle_sym_value(menu
);
1058 gtk_tree_view_expand_row(view
, path
, TRUE
);
1061 if (col
== COL_VALUE
) {
1062 toggle_sym_value(menu
);
1063 gtk_tree_view_expand_row(view
, path
, TRUE
);
1064 } else if (col
== COL_NO
|| col
== COL_MOD
1065 || col
== COL_YES
) {
1066 change_sym_value(menu
, col
);
1067 gtk_tree_view_expand_row(view
, path
, TRUE
);
1074 /* Key pressed: update choice */
1076 on_treeview2_key_press_event(GtkWidget
* widget
,
1077 GdkEventKey
* event
, gpointer user_data
)
1079 GtkTreeView
*view
= GTK_TREE_VIEW(widget
);
1081 GtkTreeViewColumn
*column
;
1086 gtk_tree_view_get_cursor(view
, &path
, &column
);
1090 if (event
->keyval
== GDK_space
) {
1091 if (gtk_tree_view_row_expanded(view
, path
))
1092 gtk_tree_view_collapse_row(view
, path
);
1094 gtk_tree_view_expand_row(view
, path
, FALSE
);
1097 if (event
->keyval
== GDK_KP_Enter
) {
1099 if (widget
== tree1_w
)
1102 gtk_tree_model_get_iter(model2
, &iter
, path
);
1103 gtk_tree_model_get(model2
, &iter
, COL_MENU
, &menu
, -1);
1105 if (!strcasecmp(event
->string
, "n"))
1107 else if (!strcasecmp(event
->string
, "m"))
1109 else if (!strcasecmp(event
->string
, "y"))
1113 change_sym_value(menu
, col
);
1119 /* Row selection changed: update help */
1121 on_treeview2_cursor_changed(GtkTreeView
* treeview
, gpointer user_data
)
1123 GtkTreeSelection
*selection
;
1127 selection
= gtk_tree_view_get_selection(treeview
);
1128 if (gtk_tree_selection_get_selected(selection
, &model2
, &iter
)) {
1129 gtk_tree_model_get(model2
, &iter
, COL_MENU
, &menu
, -1);
1130 text_insert_help(menu
);
1135 /* User click: display sub-tree in the right frame. */
1137 on_treeview1_button_press_event(GtkWidget
* widget
,
1138 GdkEventButton
* event
, gpointer user_data
)
1140 GtkTreeView
*view
= GTK_TREE_VIEW(widget
);
1142 GtkTreeViewColumn
*column
;
1146 gint tx
= (gint
) event
->x
;
1147 gint ty
= (gint
) event
->y
;
1150 gtk_tree_view_get_path_at_pos(view
, tx
, ty
, &path
, &column
, &cx
,
1155 gtk_tree_model_get_iter(model1
, &iter
, path
);
1156 gtk_tree_model_get(model1
, &iter
, COL_MENU
, &menu
, -1);
1158 if (event
->type
== GDK_2BUTTON_PRESS
) {
1159 toggle_sym_value(menu
);
1161 display_tree_part();
1164 display_tree_part();
1167 gtk_widget_realize(tree2_w
);
1168 gtk_tree_view_set_cursor(view
, path
, NULL
, FALSE
);
1169 gtk_widget_grab_focus(tree2_w
);
1175 /* Conf management */
1178 /* Fill a row of strings */
1179 static gchar
**fill_row(struct menu
*menu
)
1181 static gchar
*row
[COL_NUMBER
];
1182 struct symbol
*sym
= menu
->sym
;
1186 enum prop_type ptype
;
1189 for (i
= COL_OPTION
; i
<= COL_COLOR
; i
++)
1191 bzero(row
, sizeof(row
));
1194 g_strdup_printf("%s %s", menu_get_prompt(menu
),
1196 flags
& SYMBOL_NEW
? "(NEW)" : "") :
1199 if (show_all
&& !menu_is_visible(menu
))
1200 row
[COL_COLOR
] = g_strdup("DarkGray");
1202 row
[COL_COLOR
] = g_strdup("Black");
1204 ptype
= menu
->prompt
? menu
->prompt
->type
: P_UNKNOWN
;
1207 row
[COL_PIXBUF
] = (gchar
*) xpm_menu
;
1208 if (view_mode
== SINGLE_VIEW
)
1209 row
[COL_PIXVIS
] = GINT_TO_POINTER(TRUE
);
1210 row
[COL_BTNVIS
] = GINT_TO_POINTER(FALSE
);
1213 row
[COL_PIXBUF
] = (gchar
*) xpm_void
;
1214 row
[COL_PIXVIS
] = GINT_TO_POINTER(FALSE
);
1215 row
[COL_BTNVIS
] = GINT_TO_POINTER(FALSE
);
1218 row
[COL_PIXBUF
] = (gchar
*) xpm_void
;
1219 row
[COL_PIXVIS
] = GINT_TO_POINTER(FALSE
);
1220 row
[COL_BTNVIS
] = GINT_TO_POINTER(TRUE
);
1226 row
[COL_NAME
] = g_strdup(sym
->name
);
1228 sym_calc_value(sym
);
1229 sym
->flags
&= ~SYMBOL_CHANGED
;
1231 if (sym_is_choice(sym
)) { // parse childs for getting final value
1233 struct symbol
*def_sym
= sym_get_choice_value(sym
);
1234 struct menu
*def_menu
= NULL
;
1236 row
[COL_BTNVIS
] = GINT_TO_POINTER(FALSE
);
1238 for (child
= menu
->list
; child
; child
= child
->next
) {
1239 if (menu_is_visible(child
)
1240 && child
->sym
== def_sym
)
1246 g_strdup(menu_get_prompt(def_menu
));
1248 if(sym
->flags
& SYMBOL_CHOICEVAL
)
1249 row
[COL_BTNRAD
] = GINT_TO_POINTER(TRUE
);
1251 stype
= sym_get_type(sym
);
1254 if(GPOINTER_TO_INT(row
[COL_PIXVIS
]) == FALSE
)
1255 row
[COL_BTNVIS
] = GINT_TO_POINTER(TRUE
);
1256 if (sym_is_choice(sym
))
1259 val
= sym_get_tristate_value(sym
);
1262 row
[COL_NO
] = g_strdup("N");
1263 row
[COL_VALUE
] = g_strdup("N");
1264 row
[COL_BTNACT
] = GINT_TO_POINTER(FALSE
);
1265 row
[COL_BTNINC
] = GINT_TO_POINTER(FALSE
);
1268 row
[COL_MOD
] = g_strdup("M");
1269 row
[COL_VALUE
] = g_strdup("M");
1270 row
[COL_BTNINC
] = GINT_TO_POINTER(TRUE
);
1273 row
[COL_YES
] = g_strdup("Y");
1274 row
[COL_VALUE
] = g_strdup("Y");
1275 row
[COL_BTNACT
] = GINT_TO_POINTER(TRUE
);
1276 row
[COL_BTNINC
] = GINT_TO_POINTER(FALSE
);
1280 if (val
!= no
&& sym_tristate_within_range(sym
, no
))
1281 row
[COL_NO
] = g_strdup("_");
1282 if (val
!= mod
&& sym_tristate_within_range(sym
, mod
))
1283 row
[COL_MOD
] = g_strdup("_");
1284 if (val
!= yes
&& sym_tristate_within_range(sym
, yes
))
1285 row
[COL_YES
] = g_strdup("_");
1290 def
= sym_get_string_value(sym
);
1291 row
[COL_VALUE
] = g_strdup(def
);
1292 row
[COL_EDIT
] = GINT_TO_POINTER(TRUE
);
1293 row
[COL_BTNVIS
] = GINT_TO_POINTER(FALSE
);
1301 /* Set the node content with a row of strings */
1302 static void set_node(GtkTreeIter
* node
, struct menu
*menu
, gchar
** row
)
1308 pix
= gdk_pixbuf_new_from_xpm_data((const char **)
1311 gdk_color_parse(row
[COL_COLOR
], &color
);
1312 gdk_colormap_alloc_colors(gdk_colormap_get_system(), &color
, 1,
1313 FALSE
, FALSE
, &success
);
1315 gtk_tree_store_set(tree
, node
,
1316 COL_OPTION
, row
[COL_OPTION
],
1317 COL_NAME
, row
[COL_NAME
],
1318 COL_NO
, row
[COL_NO
],
1319 COL_MOD
, row
[COL_MOD
],
1320 COL_YES
, row
[COL_YES
],
1321 COL_VALUE
, row
[COL_VALUE
],
1322 COL_MENU
, (gpointer
) menu
,
1324 COL_EDIT
, GPOINTER_TO_INT(row
[COL_EDIT
]),
1326 COL_PIXVIS
, GPOINTER_TO_INT(row
[COL_PIXVIS
]),
1327 COL_BTNVIS
, GPOINTER_TO_INT(row
[COL_BTNVIS
]),
1328 COL_BTNACT
, GPOINTER_TO_INT(row
[COL_BTNACT
]),
1329 COL_BTNINC
, GPOINTER_TO_INT(row
[COL_BTNINC
]),
1330 COL_BTNRAD
, GPOINTER_TO_INT(row
[COL_BTNRAD
]),
1333 g_object_unref(pix
);
1337 /* Add a node to the tree */
1338 static void place_node(struct menu
*menu
, char **row
)
1340 GtkTreeIter
*parent
= parents
[indent
- 1];
1341 GtkTreeIter
*node
= parents
[indent
];
1343 gtk_tree_store_append(tree
, node
, parent
);
1344 set_node(node
, menu
, row
);
1348 /* Find a node in the GTK+ tree */
1349 static GtkTreeIter found
;
1352 * Find a menu in the GtkTree starting at parent.
1354 GtkTreeIter
*gtktree_iter_find_node(GtkTreeIter
* parent
,
1355 struct menu
*tofind
)
1358 GtkTreeIter
*child
= &iter
;
1362 valid
= gtk_tree_model_iter_children(model2
, child
, parent
);
1366 gtk_tree_model_get(model2
, child
, 6, &menu
, -1);
1368 if (menu
== tofind
) {
1369 memcpy(&found
, child
, sizeof(GtkTreeIter
));
1373 ret
= gtktree_iter_find_node(child
, tofind
);
1377 valid
= gtk_tree_model_iter_next(model2
, child
);
1385 * Update the tree by adding/removing entries
1386 * Does not change other nodes
1388 static void update_tree(struct menu
*src
, GtkTreeIter
* dst
)
1390 struct menu
*child1
;
1391 GtkTreeIter iter
, tmp
;
1392 GtkTreeIter
*child2
= &iter
;
1394 GtkTreeIter
*sibling
;
1396 struct property
*prop
;
1397 struct menu
*menu1
, *menu2
;
1399 if (src
== &rootmenu
)
1402 valid
= gtk_tree_model_iter_children(model2
, child2
, dst
);
1403 for (child1
= src
->list
; child1
; child1
= child1
->next
) {
1405 prop
= child1
->prompt
;
1411 gtk_tree_model_get(model2
, child2
, COL_MENU
,
1414 menu2
= NULL
; // force adding of a first child
1417 printf("%*c%s | %s\n", indent
, ' ',
1418 menu1
? menu_get_prompt(menu1
) : "nil",
1419 menu2
? menu_get_prompt(menu2
) : "nil");
1422 if (!menu_is_visible(child1
) && !show_all
) { // remove node
1423 if (gtktree_iter_find_node(dst
, menu1
) != NULL
) {
1424 memcpy(&tmp
, child2
, sizeof(GtkTreeIter
));
1425 valid
= gtk_tree_model_iter_next(model2
,
1427 gtk_tree_store_remove(tree2
, &tmp
);
1429 return; // next parent
1431 goto reparse
; // next child
1436 if (menu1
!= menu2
) {
1437 if (gtktree_iter_find_node(dst
, menu1
) == NULL
) { // add node
1438 if (!valid
&& !menu2
)
1442 gtk_tree_store_insert_before(tree2
,
1445 set_node(child2
, menu1
, fill_row(menu1
));
1448 } else { // remove node
1449 memcpy(&tmp
, child2
, sizeof(GtkTreeIter
));
1450 valid
= gtk_tree_model_iter_next(model2
,
1452 gtk_tree_store_remove(tree2
, &tmp
);
1454 return; // next parent
1456 goto reparse
; // next child
1458 } else if (sym
&& (sym
->flags
& SYMBOL_CHANGED
)) {
1459 set_node(child2
, menu1
, fill_row(menu1
));
1463 update_tree(child1
, child2
);
1466 valid
= gtk_tree_model_iter_next(model2
, child2
);
1471 /* Display the whole tree (single/split/full view) */
1472 static void display_tree(struct menu
*menu
)
1475 struct property
*prop
;
1477 enum prop_type ptype
;
1479 if (menu
== &rootmenu
) {
1481 current
= &rootmenu
;
1484 for (child
= menu
->list
; child
; child
= child
->next
) {
1485 prop
= child
->prompt
;
1487 ptype
= prop
? prop
->type
: P_UNKNOWN
;
1490 sym
->flags
&= ~SYMBOL_CHANGED
;
1492 if ((view_mode
== SPLIT_VIEW
) && !(child
->flags
& MENU_ROOT
) &&
1496 if ((view_mode
== SPLIT_VIEW
) && (child
->flags
& MENU_ROOT
) &&
1500 if (menu_is_visible(child
) || show_all
)
1501 place_node(child
, fill_row(child
));
1503 printf("%*c%s: ", indent
, ' ', menu_get_prompt(child
));
1504 printf("%s", child
->flags
& MENU_ROOT
? "rootmenu | " : "");
1505 dbg_print_ptype(ptype
);
1508 dbg_print_stype(sym
->type
);
1510 dbg_print_flags(sym
->flags
);
1515 if ((view_mode
!= FULL_VIEW
) && (ptype
== P_MENU
)
1519 if (((menu != &rootmenu) && !(menu->flags & MENU_ROOT)) ||
1520 (view_mode == FULL_VIEW)
1521 || (view_mode == SPLIT_VIEW))*/
1522 if (((view_mode
== SINGLE_VIEW
) && (menu
->flags
& MENU_ROOT
))
1523 || (view_mode
== FULL_VIEW
) || (view_mode
== SPLIT_VIEW
)) {
1525 display_tree(child
);
1531 /* Display a part of the tree starting at current node (single/split view) */
1532 static void display_tree_part(void)
1535 gtk_tree_store_clear(tree2
);
1536 if(view_mode
== SINGLE_VIEW
)
1537 display_tree(current
);
1538 else if(view_mode
== SPLIT_VIEW
)
1539 display_tree(browsed
);
1540 gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w
));
1543 /* Display the list in the left frame (split view) */
1544 static void display_list(void)
1547 gtk_tree_store_clear(tree1
);
1550 display_tree(&rootmenu
);
1551 gtk_tree_view_expand_all(GTK_TREE_VIEW(tree1_w
));
1555 void fixup_rootmenu(struct menu
*menu
)
1558 static int menu_cnt
= 0;
1560 menu
->flags
|= MENU_ROOT
;
1561 for (child
= menu
->list
; child
; child
= child
->next
) {
1562 if (child
->prompt
&& child
->prompt
->type
== P_MENU
) {
1564 fixup_rootmenu(child
);
1566 } else if (!menu_cnt
)
1567 fixup_rootmenu(child
);
1575 int main(int ac
, char *av
[])
1581 #ifndef LKC_DIRECT_LINK
1590 //add_pixmap_directory (PACKAGE_DATA_DIR "/" PACKAGE "/pixmaps");
1591 //add_pixmap_directory (PACKAGE_SOURCE_DIR "/pixmaps");
1593 /* Determine GUI path */
1594 env
= getenv(SRCTREE
);
1596 glade_file
= g_strconcat(env
, "/scripts/kconfig/gconf.glade", NULL
);
1597 else if (av
[0][0] == '/')
1598 glade_file
= g_strconcat(av
[0], ".glade", NULL
);
1600 glade_file
= g_strconcat(g_get_current_dir(), "/", av
[0], ".glade", NULL
);
1602 /* Load the interface and connect signals */
1603 init_main_window(glade_file
);
1609 if (ac
> 1 && av
[1][0] == '-') {
1616 printf("%s <config>\n", av
[0]);
1624 fixup_rootmenu(&rootmenu
);
1627 switch (view_mode
) {
1629 display_tree_part();
1635 display_tree(&rootmenu
);